Skip to content

Commit

Permalink
Inertia Stack (#44)
Browse files Browse the repository at this point in the history
Adds the Inertia stack to Laravel Breeze
  • Loading branch information
taylorotwell authored Feb 17, 2021
1 parent a3639be commit d66e1af
Show file tree
Hide file tree
Showing 82 changed files with 1,831 additions and 15 deletions.
168 changes: 153 additions & 15 deletions src/Console/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
use Symfony\Component\Process\Process;

class InstallCommand extends Command
{
Expand All @@ -12,7 +14,9 @@ class InstallCommand extends Command
*
* @var string
*/
protected $signature = 'breeze:install';
protected $signature = 'breeze:install
{--inertia : Indicates that the Inertia stack should be installed}
{--composer=global : Absolute path to the Composer binary which should be used to install packages}';

/**
* The console command description.
Expand All @@ -28,6 +32,10 @@ class InstallCommand extends Command
*/
public function handle()
{
if ($this->option('inertia')) {
return $this->installInertiaStack();
}

// NPM Packages...
$this->updateNodePackages(function ($packages) {
return [
Expand All @@ -42,49 +50,179 @@ public function handle()

// Controllers...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Controllers/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/App/Http/Controllers/Auth', app_path('Http/Controllers/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/App/Http/Controllers/Auth', app_path('Http/Controllers/Auth'));

// Requests...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Requests/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/App/Http/Requests/Auth', app_path('Http/Requests/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/App/Http/Requests/Auth', app_path('Http/Requests/Auth'));

// Views...
(new Filesystem)->ensureDirectoryExists(resource_path('views/auth'));
(new Filesystem)->ensureDirectoryExists(resource_path('views/layouts'));
(new Filesystem)->ensureDirectoryExists(resource_path('views/components'));

(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/resources/views/auth', resource_path('views/auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/resources/views/layouts', resource_path('views/layouts'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/resources/views/components', resource_path('views/components'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/resources/views/auth', resource_path('views/auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/resources/views/layouts', resource_path('views/layouts'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/resources/views/components', resource_path('views/components'));

copy(__DIR__.'/../../stubs/resources/views/dashboard.blade.php', resource_path('views/dashboard.blade.php'));
copy(__DIR__.'/../../stubs/default/resources/views/dashboard.blade.php', resource_path('views/dashboard.blade.php'));

// Components...
(new Filesystem)->ensureDirectoryExists(app_path('View/Components'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/App/View/Components', app_path('View/Components'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/App/View/Components', app_path('View/Components'));

// Tests...
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/tests/Feature', base_path('tests/Feature'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/tests/Feature', base_path('tests/Feature'));

// Routes...
copy(__DIR__.'/../../stubs/routes/web.php', base_path('routes/web.php'));
copy(__DIR__.'/../../stubs/routes/auth.php', base_path('routes/auth.php'));
copy(__DIR__.'/../../stubs/default/routes/web.php', base_path('routes/web.php'));
copy(__DIR__.'/../../stubs/default/routes/auth.php', base_path('routes/auth.php'));

// "Dashboard" Route...
$this->replaceInFile('/home', '/dashboard', resource_path('views/welcome.blade.php'));
$this->replaceInFile('Home', 'Dashboard', resource_path('views/welcome.blade.php'));
$this->replaceInFile('/home', '/dashboard', app_path('Providers/RouteServiceProvider.php'));

// Tailwind / Webpack...
copy(__DIR__.'/../../stubs/tailwind.config.js', base_path('tailwind.config.js'));
copy(__DIR__.'/../../stubs/webpack.mix.js', base_path('webpack.mix.js'));
copy(__DIR__.'/../../stubs/resources/css/app.css', resource_path('css/app.css'));
copy(__DIR__.'/../../stubs/resources/js/app.js', resource_path('js/app.js'));
copy(__DIR__.'/../../stubs/default/tailwind.config.js', base_path('tailwind.config.js'));
copy(__DIR__.'/../../stubs/default/webpack.mix.js', base_path('webpack.mix.js'));
copy(__DIR__.'/../../stubs/default/webpack.config.js', base_path('webpack.config.js'));
copy(__DIR__.'/../../stubs/default/resources/css/app.css', resource_path('css/app.css'));
copy(__DIR__.'/../../stubs/default/resources/js/app.js', resource_path('js/app.js'));

$this->info('Breeze scaffolding installed successfully.');
$this->comment('Please execute the "npm install && npm run dev" command to build your assets.');
}

/**
* Install the Inertia Breeze stack.
*
* @return void
*/
protected function installInertiaStack()
{
// Install Inertia...
$this->requireComposerPackages('inertiajs/inertia-laravel:^0.3.5', 'laravel/sanctum:^2.6', 'tightenco/ziggy:^1.0');

// NPM Packages...
$this->updateNodePackages(function ($packages) {
return [
'@inertiajs/inertia' => '^0.8.4',
'@inertiajs/inertia-vue3' => '^0.3.5',
'@tailwindcss/forms' => '^0.2.1',
'@vue/compiler-sfc' => '^3.0.5',
'autoprefixer' => '^10.2.4',
'postcss' => '^8.2.1',
'postcss-import' => '^12.0.1',
'tailwindcss' => '^2.0.3',
'vue' => '^3.0.5',
'vue-loader' => '^16.1.2',
] + $packages;
});

// Controllers...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Controllers/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/App/Http/Controllers/Auth', app_path('Http/Controllers/Auth'));

// Requests...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Requests/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/App/Http/Requests/Auth', app_path('Http/Requests/Auth'));

// Middleware...
$this->installMiddlewareAfter('SubstituteBindings::class', '\App\Http\Middleware\HandleInertiaRequests::class');

copy(__DIR__.'/../../stubs/inertia/app/Http/Middleware/HandleInertiaRequests.php', app_path('Http/Middleware/HandleInertiaRequests.php'));

// Views...
copy(__DIR__.'/../../stubs/inertia/resources/views/app.blade.php', resource_path('views/app.blade.php'));

// Components + Pages...
(new Filesystem)->ensureDirectoryExists(resource_path('js/Components'));
(new Filesystem)->ensureDirectoryExists(resource_path('js/Layouts'));
(new Filesystem)->ensureDirectoryExists(resource_path('js/Pages'));

(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/resources/js/Components', resource_path('js/Components'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/resources/js/Layouts', resource_path('js/Layouts'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/resources/js/Pages', resource_path('js/Pages'));

// Tests...
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/tests/Feature', base_path('tests/Feature'));

// Routes...
copy(__DIR__.'/../../stubs/inertia/routes/web.php', base_path('routes/web.php'));
copy(__DIR__.'/../../stubs/inertia/routes/auth.php', base_path('routes/auth.php'));

// "Dashboard" Route...
$this->replaceInFile('/home', '/dashboard', resource_path('js/Pages/Welcome.vue'));
$this->replaceInFile('Home', 'Dashboard', resource_path('js/Pages/Welcome.vue'));
$this->replaceInFile('/home', '/dashboard', app_path('Providers/RouteServiceProvider.php'));

// Tailwind / Webpack...
copy(__DIR__.'/../../stubs/inertia/tailwind.config.js', base_path('tailwind.config.js'));
copy(__DIR__.'/../../stubs/inertia/webpack.mix.js', base_path('webpack.mix.js'));
copy(__DIR__.'/../../stubs/inertia/resources/css/app.css', resource_path('css/app.css'));
copy(__DIR__.'/../../stubs/inertia/resources/js/app.js', resource_path('js/app.js'));

$this->info('Breeze scaffolding installed successfully.');
$this->comment('Please execute the "npm install && npm run dev" command to build your assets.');
}

/**
* Install the middleware to a group in the application Http Kernel.
*
* @param string $after
* @param string $name
* @param string $group
* @return void
*/
protected function installMiddlewareAfter($after, $name, $group = 'web')
{
$httpKernel = file_get_contents(app_path('Http/Kernel.php'));

$middlewareGroups = Str::before(Str::after($httpKernel, '$middlewareGroups = ['), '];');
$middlewareGroup = Str::before(Str::after($middlewareGroups, "'$group' => ["), '],');

if (! Str::contains($middlewareGroup, $name)) {
$modifiedMiddlewareGroup = str_replace(
$after.',',
$after.','.PHP_EOL.' '.$name.',',
$middlewareGroup,
);

file_put_contents(app_path('Http/Kernel.php'), str_replace(
$middlewareGroups,
str_replace($middlewareGroup, $modifiedMiddlewareGroup, $middlewareGroups),
$httpKernel
));
}
}

/**
* Installs the given Composer Packages into the application.
*
* @param mixed $packages
* @return void
*/
protected function requireComposerPackages($packages)
{
$composer = $this->option('composer');

if ($composer !== 'global') {
$command = ['php', $composer, 'require'];
}

$command = array_merge(
$command ?? ['composer', 'require'],
is_array($packages) ? $packages : func_get_args()
);

(new Process($command, base_path(), ['COMPOSER_MEMORY_LIMIT' => '-1']))
->setTimeout(null)
->run(function ($type, $output) {
$this->output->write($output);
});
}

/**
* Update the "package.json" file.
*
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;

class AuthenticatedSessionController extends Controller
{
/**
* Display the login view.
*
* @return \Illuminate\View\View
*/
public function create()
{
return Inertia::render('Auth/Login', [
'canResetPassword' => Route::has('password.request'),
'status' => session('status'),
]);
}

/**
* Handle an incoming authentication request.
*
* @param \App\Http\Requests\Auth\LoginRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$request->authenticate();

$request->session()->regenerate();

return redirect()->intended(RouteServiceProvider::HOME);
}

/**
* Destroy an authenticated session.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Request $request)
{
Auth::guard('web')->logout();

$request->session()->invalidate();

$request->session()->regenerateToken();

return redirect('/');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;

class ConfirmablePasswordController extends Controller
{
/**
* Show the confirm password view.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\View\View
*/
public function show(Request $request)
{
return Inertia::render('Auth/ConfirmPassword');
}

/**
* Confirm the user's password.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function store(Request $request)
{
if (! Auth::guard('web')->validate([
'email' => $request->user()->email,
'password' => $request->password,
])) {
throw ValidationException::withMessages([
'password' => __('auth.password'),
]);
}

$request->session()->put('auth.password_confirmed_at', time());

return redirect()->intended(RouteServiceProvider::HOME);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;

class EmailVerificationNotificationController extends Controller
{
/**
* Send a new email verification notification.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
if ($request->user()->hasVerifiedEmail()) {
return redirect()->intended(RouteServiceProvider::HOME);
}

$request->user()->sendEmailVerificationNotification();

return back()->with('status', 'verification-link-sent');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Inertia\Inertia;

class EmailVerificationPromptController extends Controller
{
/**
* Display the email verification prompt.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function __invoke(Request $request)
{
return $request->user()->hasVerifiedEmail()
? redirect()->intended(RouteServiceProvider::HOME)
: Inertia::render('Auth/VerifyEmail', ['status' => session('status')]);
}
}
Loading

0 comments on commit d66e1af

Please sign in to comment.