CRUD - Cadastrar, listar, editar e apagar com Laravel 11 - Parte 1


Neste tutorial, será apresentado como criar formulários de cadastro e edição, além de criar as páginas de listagem e visualização, e o botão de apagar, com Laravel 11.

Primeiramente, será demonstrado como criar o formulário para cadastrar usuários no banco de dados.

Em seguida, será explicado como criar a página para listar os registros do banco de dados, incluindo a paginação.

Por fim, será mostrado como integrar o framework Bootstrap no Laravel com Vite.

Download do código fonte desenvolvido na aula: Download

PlayList sobre Laravel 11: Acessar

Como usar SweetAlert2: Acessar

Receber as aulas gratuitas do curso de Laravel: Acessar


Para começar, é criado o projeto com Laravel 11 usando o Composer.

composer create-project laravel/laravel .

Alteradas as informações do projeto no arquivo .env.

APP_NAME=Celke
APP_ENV=local

APP_DEBUG=true
APP_TIMEZONE=America/Sao_Paulo
APP_URL=http://127.0.0.1:8000

APP_LOCALE=pt-BR

Também alteradas as credenciais do banco de dados no arquivo .env.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=celke
DB_USERNAME=root
DB_PASSWORD=

Com as credenciais do banco de dados corretas no arquivo .env, é necessário executar as migrations que são criadas por padrão no Laravel.

php artisan migrate

Em seguida, no arquivo 'routes/web.php', é criada a rota para a página que lista os usuários.

Route::get('/', [UserController::class, 'index'])->name('user.index');

Criada a controller UserController.

php artisan make:controller UserController

Nela, é implementado o método index para recuperar os registros do banco de dados e também carregar a view.

public function index()
{

    // Recuperar os registros do banco dados
    $users = User::orderByDesc('id')->get();

    // Carregar a VIEW
    return view('users.index', ['users' => $users]);
}

Criada a view para listar os usuários.

php artisan make:view users/show

Nela, são listados os registros e incluído o layout 'layouts.admin'.

@extends('layouts.admin')

@section('content')
    <div class="card mt-4 mb-4 border-light shadow">

        <div class="card-header hstack gap-2">
            <span>Listar Usuários</span>

            <span class="ms-auto">
                <a href="{{ route('user.create') }}" class="btn btn-success btn-sm">Cadastrar</a>
            </span>
        </div>

        <div class="card-body">

            <x-alert />

            <table class="table">
                <thead>
                    <tr>
                        <th scope="col">ID</th>
                        <th scope="col">Nome</th>
                        <th scope="col">E-mail</th>
                        <th scope="col" class="text-center">Ações</th>
                    </tr>
                </thead>
                <tbody>

                    @forelse ($users as $user)
                        <tr>
                            <th>{{ $user->id }}</th>
                            <td>{{ $user->name }}</td>
                            <td>{{ $user->email }}</td>
                            <td class="text-center">
                                <a href="{{ route('user.show', ['user' => $user->id]) }}"
                                    class="btn btn-primary btn-sm">Visualizar</a>
                                <a href="{{ route('user.edit', ['user' => $user->id]) }}"
                                    class="btn btn-warning btn-sm">Editar</a>
                                <form method="POST" action="{{ route('user.destroy', ['user' => $user->id]) }}"
                                    class="d-inline">
                                    @csrf
                                    @method('delete')
                                    <button type="submit" class="btn btn-danger btn-sm"
                                        onclick="return confirm('Tem certeza que deseja apagar este registro?')">Apagar</button>
                                </form>
                            </td>
                        </tr>
                    @empty
                    @endforelse
                </tbody>
            </table>
        </div>
    </div>
@endsection

Para criar o layout 'resources/views/layouts/admin.blade.php', é acrescentada a estrutura básica do HTML e definido o local onde deve ser carregado o conteúdo das views através do @yield('content').

<!DOCTYPE html>
<html lang="pt-BR">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    @vite(['resources/sass/app.scss', 'resources/js/app.js'])

    <title>Celke</title>
</head>

<body>

    <header class="p-3 text-bg-primary">
        <div class="container">
            <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
                <a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
                    <svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap">
                        <use xlink:href="#bootstrap" />
                    </svg>
                </a>

                <ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
                    <li><a href="{{ route('user.index') }}" class="nav-link px-2 text-white">Home</a></li>
                    <li><a href="{{ route('user.index') }}" class="nav-link px-2 text-white">Usuários</a></li>
                </ul>

                <div class="text-end">
                    <button type="button" class="btn btn-outline-light me-2">Login</button>
                </div>
            </div>
        </div>
    </header>

    <div class="container">
        @yield('content')
    </div>

</body>

</html>

O próximo passo é implementar a página com o formulário para cadastrar usuários no banco de dados. Primeiro, é criada a rota no arquivo 'routes/web.php'.

Route::get('/create-user', [UserController::class, 'create'])->name('user.create');

Em seguida, na controller 'UserController', criado o método 'show' para carregar a view com o formulário.

public function create(User $user)
{ return view('users.create');
}

Criada a view com o formulário para cadastrar usuário.

php artisan make:view users/create

Na mesma, é implementado o formulário, incluído o layout 'layouts.admin' e enviados os dados para a rota 'user.store'.

@extends('layouts.admin')

@section('content')
    <div class="card mt-4 mb-4 border-light shadow">

        <div class="card-header hstack gap-2">
            <span>Cadastrar Usuário</span>

            <span class="ms-auto d-sm-flex flex-row">

                <a href="{{ route('user.index') }}" class="btn btn-info btn-sm me-1">Listar</a>

            </span>
        </div>

        <div class="card-body">

            <x-alert />

            <form action="{{ route('user-store') }}" method="POST" class="row g-3">
                @csrf
                @method('POST')

                <div class="col-md-12">
                    <label for="name" class="form-label">Nome</label>
                    <input type="text" name="name" class="form-control" id="name" placeholder="Nome completo"
                        value="{{ old('name') }}">
                </div>

                <div class="col-md-6">
                    <label for="email" class="form-label">E-mail</label>
                    <input type="email" name="email" class="form-control" id="email"
                        placeholder="Melhor e-mail do usuário" value="{{ old('email') }}">
                </div>

                <div class="col-md-6">
                    <label for="password" class="form-label">Senha</label>
                    <input type="password" name="password" class="form-control" id="password"
                        placeholder="Senha com no mínimo 6 caracteres" value="{{ old('password') }}">
                </div>

                <div class="col-12">
                    <button type="submit" class="btn btn-success btn-sm">Cadastrar</button>
                </div>

            </form>
        </div>
    </div>
@endsection

Os dados do formulário serão enviados para a rota 'user.store', que foi criada no arquivo 'routes/web.php'.

Route::get('/store-user', [UserController::class, 'store'])->name('user.store');

A rota chama o método 'store' da controller 'UserController', que recebe os dados, realiza a validação com a classe 'UserRequest' e salva no banco de dados.

public function store(UserRequest $request)
{
    // Validar o formulário
    $request->validated();
    
    // Cadastrar o usuário no BD
    User::create([
        'name' => $request->name,
        'email' => $request->email,
        'password' => $request->password,
    ]);

    // Redirecionar o usuário, enviar a mensagem de sucesso
    return redirect()->route('user.index')->with('success', 'Usuário cadastrado com sucesso!');

}

É necessário criar a classe para validar os dados do formulário com o comando.

php artisan make:request UserRequest

No arquivo 'app/Http/Request/UserRequest', implementada a validação.

class UserRequest extends FormRequest
{
    
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {

        $userId = $this->route('user');

        return [
            'name' => 'required',
            'email' => 'required|email|unique:users,email,' . ($userId ? $userId->id : null),
            'password' => 'required|min:6',
        ];
    }

    public function messages(): array 
    {
        return[
            'name.required' => 'Campo nome é obrigatório!',
            'email.required' => 'Campo e-mail é obrigatório!',
            'email.email' => 'Necessário enviar e-mail válido!',
            'email.unique' => 'O e-mail já está cadastrado!',
            'password.required' => 'Campo senha é obrigatório!',
            'password.min' => 'Senha com no mínimo :min caracteres!',
        ];
    }
}

Após validar os dados e realizar o cadastro do registro no banco de dados, é criada a mensagem de sucesso e redirecionado para a página de listagem.

Para apresentar a mensagem de sucesso, é criado o componente 'alert' com o comando:

php artisan make:component alert --view

No componente criado em 'resources/views/components/alert.blade.php', foi implementado para verificar se existe uma mensagem de sucesso ou erro na validação dos dados do formulário e imprimi-la.

@if (session('success'))
    <div class="alert alert-success" role="alert">
        {{ session('success') }}
    </div>
@endif

@if ($errors->any())
    <div class="alert alert-danger" role="alert">
        @foreach ($errors->all() as $error)
            {{ $error }}<br>
        @endforeach
    </div>
@endif

Em seguida, é implementada a página para visualizar os detalhes do usuário. É necessário criar a rota.

Route::get('/show-user/{user}', [UserController::class, 'show'])->name('user.show');

Foi implementado na controller 'UserController' o método 'show', que recupera os dados do usuário e os envia para a view.

public function show(User $user)
{
    return view('users.show', ['user' => $user]);
}

Criada a view com o comando.

php artisan make:view users/show

Na view criada, 'resources/views/users/show.blade.php', são impressos os dados do usuário.

@extends('layouts.admin')

@section('content')
    <div class="card mt-4 mb-4 border-light shadow">

        <div class="card-header hstack gap-2">
            <span>Visualizar Usuário</span>

            <span class="ms-auto d-sm-flex flex-row">

                <a href="{{ route('user.index') }}" class="btn btn-info btn-sm me-1">Listar</a>
                <a href="{{ route('user.edit', ['user' => $user->id]) }}" class="btn btn-warning btn-sm me-1">Editar</a>
                <form method="POST" action="{{ route('user.destroy', ['user' => $user->id]) }}">
                    @csrf
                    @method('delete')
                    <button type="submit" class="btn btn-danger btn-sm me-1"
                        onclick="return confirm('Tem certeza que deseja apagar este registro?')">Apagar</button>
                </form>
            </span>
        </div>

        <div class="card-body">

            <x-alert />

            <dl class="row">

                <dt class="col-sm-3">ID</dt>
                <dd class="col-sm-9">{{ $user->id }}</dd>

                <dt class="col-sm-3">Nome</dt>
                <dd class="col-sm-9">{{ $user->name }}</dd>

                <dt class="col-sm-3">E-mail</dt>
                <dd class="col-sm-9">{{ $user->email }}</dd>

                <dt class="col-sm-3">Cadastrado</dt>
                <dd class="col-sm-9">{{ \Carbon\Carbon::parse($user->created_at)->format('d/m/Y H:i:s') }}</dd>

                <dt class="col-sm-3">Editado</dt>
                <dd class="col-sm-9">{{ \Carbon\Carbon::parse($user->updated_at)->format('d/m/Y H:i:s') }}</dd>

            </dl>
        </div>
    </div>
@endsection

O próximo passo é implementar o formulário para editar o usuário. Esse conteúdo é abordado na parte 2 deste tutorial, através do link CRUD - Cadastrar, listar, editar e apagar com Laravel 11 - Parte 2.


Baixar o código-fonte completo do projeto.

Bom, era isso. Espero que o tutorial tenha sido útil!