diff --git a/src/Console/Commands/InstallCollaboration.php b/src/Console/Commands/InstallCollaboration.php new file mode 100644 index 0000000000..a890afe032 --- /dev/null +++ b/src/Console/Commands/InstallCollaboration.php @@ -0,0 +1,200 @@ + Composer::withoutQueue()->throwOnFailure()->require('statamic/collaboration'), + 'Installing the statamic/collaboration addon...' + ); + + $this->components->info('Installed statamic/collaboration addon'); + } + + $this->enableBroadcasting(); + $this->installBroadcastingDriver(); + } + + protected function enableBroadcasting(): void + { + // TODO: Only attempt to enable broadcasting if it's not already enabled. + + if (version_compare(app()->version(), '11', '<')) { + $this->enableBroadcastServiceProvider(); + $this->components->info("Broadcasting enabled successfully."); + + return; + } + + spin( + callback: function () { + Process::run([ + (new PhpExecutableFinder())->find(false) ?: 'php', + defined('ARTISAN_BINARY') ? ARTISAN_BINARY : 'artisan', + 'install:broadcasting', + '--without-reverb', + '--without-node', + ]); + }, + message: 'Enabling broadcasting...' + ); + + $this->components->info("Broadcasting enabled successfully."); + } + + protected function installBroadcastingDriver(): void + { + $driver = select( + label: 'Which broadcasting driver would you like to use?', + options: ['Laravel Reverb', 'Pusher', 'Other'], + ); + + if ($driver === 'Laravel Reverb') { + spin( + callback: function () { + Composer::withoutQueue()->throwOnFailure()->require('laravel/reverb', '@beta'); + + Process::run([ + (new PhpExecutableFinder())->find(false) ?: 'php', + defined('ARTISAN_BINARY') ? ARTISAN_BINARY : 'artisan', + 'reverb:install', + ]); + }, + message: 'Installing Laravel Reverb...' + ); + + $this->components->info('Laravel Reverb installed successfully.'); + } + + if ($driver === 'Pusher') { + spin( + callback: function () { + Composer::withoutQueue()->throwOnFailure()->require('pusher/pusher-php-server'); + + $this->addPusherEnvironmentVariables(); + $this->updateBroadcastingDriver('pusher'); + }, + message: 'Installing Pusher...' + ); + + $this->components->info("Pusher installed successfully. Don't forget to add your Pusher credentials to your .env file."); + } + + if ($driver === 'Other') { + $this->components->warn("You'll need to install and configure your own broadcasting driver."); + } + } + + /** + * Uncomment the "BroadcastServiceProvider" in the application configuration. + * Copied from Laravel's BroadcastingInstallCommand to support Laravel 10 applications. + * + * @return void + */ + protected function enableBroadcastServiceProvider() + { + $config = ($filesystem = new Filesystem)->get(app()->configPath('app.php')); + + if (str_contains($config, '// App\Providers\BroadcastServiceProvider::class')) { + $filesystem->replaceInFile( + '// App\Providers\BroadcastServiceProvider::class', + 'App\Providers\BroadcastServiceProvider::class', + app()->configPath('app.php'), + ); + } + } + + protected function updateBroadcastingDriver(string $driver): void + { + if (File::missing($env = app()->environmentFile())) { + return; + } + + File::put( + $env, + Str::of(File::get($env))->replaceMatches('/(BROADCAST_(?:DRIVER|CONNECTION))=\w*/', function (array $matches) use ($driver) { + return $matches[1].'='.$driver; + }) + ); + } + + /** + * Add the Reverb variables to the environment file. + */ + protected function addPusherEnvironmentVariables(): void + { + if (File::missing($env = app()->environmentFile())) { + return; + } + + $contents = File::get($env); + + $variables = Arr::where([ + 'PUSHER_APP_ID' => 'PUSHER_APP_ID=', + 'PUSHER_APP_KEY' => 'PUSHER_APP_KEY=', + 'PUSHER_APP_SECRET' => 'PUSHER_APP_SECRET=', + 'PUSHER_HOST' => 'PUSHER_HOST=', + 'PUSHER_PORT' => 'PUSHER_PORT=443', + 'PUSHER_SCHEME' => 'PUSHER_SCHEME=https', + 'PUSHER_APP_CLUSTER' => 'PUSHER_APP_CLUSTER=mt1', + 'REVERB_NEW_LINE' => null, + 'VITE_PUSHER_APP_KEY' => 'VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"', + 'VITE_PUSHER_HOST' => 'VITE_PUSHER_HOST="${PUSHER_HOST}"', + 'VITE_PUSHER_PORT' => 'VITE_PUSHER_PORT="${PUSHER_PORT}"', + 'VITE_PUSHER_SCHEME' => 'VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"', + 'VITE_PUSHER_APP_CLUSTER' => 'VITE_REVERB_APP_CLUSTER="${PUSHER_APP_CLUSTER}"', + ], function ($value, $key) use ($contents) { + return ! Str::contains($contents, PHP_EOL.$key); + }); + + $variables = trim(implode(PHP_EOL, $variables)); + + if ($variables === '') { + return; + } + + File::append( + $env, + Str::endsWith($contents, PHP_EOL) ? PHP_EOL.$variables.PHP_EOL : PHP_EOL.PHP_EOL.$variables.PHP_EOL, + ); + } +} diff --git a/src/Providers/ConsoleServiceProvider.php b/src/Providers/ConsoleServiceProvider.php index 323f75206a..19789d26ef 100644 --- a/src/Providers/ConsoleServiceProvider.php +++ b/src/Providers/ConsoleServiceProvider.php @@ -15,6 +15,7 @@ class ConsoleServiceProvider extends ServiceProvider Commands\AssetsMeta::class, Commands\GlideClear::class, Commands\Install::class, + Commands\InstallCollaboration::class, Commands\InstallSsg::class, Commands\FlatCamp::class, Commands\LicenseSet::class,