pluginExists($this->pluginPath())) { $this->error('Plugin already exists!'); return; } $this->warn('Generating plugin folder structure...'); $this->generateFolderStructure(); $this->generateFiles(); $this->info('Plugin folder structure generated successfully.'); $this->warn('Installing plugin as a local composer dependency...'); $this->updateApplicationComposerFile(); $this->installPlugin(); $this->info('Plugin installed successfully.'); } /** * Generate the plugin folder structure. */ private function generateFolderStructure(): void { $pluginPath = $this->pluginPath(); foreach ($this->getFolders() as $folder) { $this->makeDirectory($pluginPath."/{$folder}"); } } /** * Get the list of folders to create. */ protected function getFolders(): array { return [ 'database/factories', 'database/migrations', 'database/seeds', 'resources/views', 'routes', 'src/Http/Controllers/Api', 'src/Http/Controllers/Web', 'src/Http/Requests', 'tests', ]; } /** * Generate necessary plugin files. * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ private function generateFiles(): void { $pluginPath = $this->pluginPath(); foreach ($this->getFiles() as $stubPath => $filePath) { $this->makeDirectory($pluginPath."/{$filePath}"); $stub = $this->files->get(__DIR__.'/stubs/'.$stubPath); $stub = $this->replacePlaceholders($stub); $this->files->put($pluginPath."/{$filePath}", $stub); } } /** * Get the list of files that should be created for the plugin. */ protected function getFiles(): array { return [ 'routes/web.stub' => 'routes/web.php', 'routes/api.stub' => 'routes/api.php', 'views/index.stub' => 'resources/views/index.blade.php', 'config.stub' => 'config/config.php', 'composer.stub' => 'composer.json', 'assets/js/app.stub' => 'resources/assets/js/app.js', 'assets/sass/app.stub' => 'resources/assets/sass/app.scss', 'webpack.stub' => 'webpack.mix.js', 'package.stub' => 'package.json', 'unit-test.stub' => 'tests/Unit/ExampleTest.php', 'feature-test.stub' => 'tests/Feature/FeatureTest.php', 'gitignore.stub' => '.gitignore', 'plugin.stub' => 'src/'.$this->studlyName().'.php', 'controller.stub' => 'src/Http/Controllers/Web/'.$this->studlyName().'Controller.php', ]; } /** * Replace placeholders within the stub files. * * @return mixed */ private function replacePlaceholders(string $stub) { return str_replace( [ '$ROOT_NAMESPACE$', '$PLUGIN_NAMESPACE$', '$VENDOR$', '$AUTHOR_NAME$', '$AUTHOR_EMAIL$', '$SNAKE_NAME$', '$STUDLY_NAME$', ], [ $this->rootNamespace(), $this->pluginNamespace(), config('plugins.composer.vendor'), config('plugins.composer.author.name'), config('plugins.composer.author.email'), $this->snakeName(), $this->studlyName(), ], $stub ); } /** * Update the main application composer file to include the * newly generated plugin. * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ private function updateApplicationComposerFile(): void { $composer = json_decode($this->files->get(base_path('composer.json')), true); $composer['repositories'][] = [ 'type' => 'path', 'url' => './plugins/'.$this->studlyName(), ]; $this->files->put( base_path('composer.json'), json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) ); } /** * Install the plugin via composer. */ private function installPlugin(): void { $pluginFullName = sprintf('%s/%s', config('plugins.composer.vendor'), $this->snakeName()); $command = Process::fromShellCommandline("composer require {$pluginFullName} \"*\""); $command->setWorkingDirectory(base_path()); $command->run(); if (! $command->isSuccessful()) { throw new ProcessFailedException($command); } } }