Criando CRUD Laravel
Visando facilitar a vida dos iniciantes em Laravel, postarei todos os exemplos abordados, você verá passo a passo a criação de um CRUD Laravel (Create Read Update Delete).
Pré-requisitos:
- Ambiente de desenvolvimento instalado e configurado
Para iniciar a criação do nosso Crud Laravel, precisamos instalar uma nova aplicação do Framework
1 . Instalando Laravel 7
composer create-project laravel/laravel --prefer-dist crud
cd crud
composer require laravelcollective/html
2. Atualizando as configuração do banco de dados
Agora faremos a configuração do banco, nome do banco, nome de usuário, senha etc.
Para isso edite o arquivo .env
:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=crud
DB_USERNAME=root
DB_PASSWORD=senha
3. Criando Migration e Model
Estamos diante de uma situação sem precedentes, Pandemia do Coronavírus. Iremos cadastrar alguns dados em nosso novo sistema.
Criaremos um Model e uma Migration, com o nome Corona
. Sempre deve se usar o nome no singular, assim não terá problemas e tudo irá funcionar com deve.
Com o exemplo Corona
ele irá criar uma tabela com o nome coronas
, e também um Model Corona
:
php artisan make:model Corona -m
Agora você pode conferir os arquivos de migração na pasta database/migrations
. Você irá encontrar os seguintes arquivos padrão e também o novo gerado com o comando anterior:
- timestamp__create_users_table.php
- timestamp_create_password_resets_table.php
- timestamp_create_failed_jobs_table.php
- timestamp_create_coronas_table.php
4. Preparando o banco de dados
edite o arquivo que acabamos de gerar timestamp_create_coronas_table.php
:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCoronasTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('coronas', function (Blueprint $table) {
$table->id();
$table->string('country_name');
$table->string('symptoms');
$table->integer('cases');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('coronas');
}
}
Existem dois tipos de funções dentro dos arquivos de migração:
- Função
up()
– Permite Criar/Atualizar tabelas, Colunas e Índices. - Função
down()
permite reverter uma operação feita pelo método up.
5. Configurando Model Corona
Adicione o código abaixo no arquivo app/Corona.php
:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Corona extends Model
{
protected $fillable = ['country_name', 'symptoms', 'cases'];
}
Em seguida, precisamos executar o seguinte comando para criar nossa tabela no banco de dados:
php artisan migrate
6. Criando um Controller
Criaremos o controlador CoronaController.php
, executando o comando:
php artisan make:controller CoronaController -r
Agora foi gerado um novo arquivo app/Http/Controllers/CoronaController.php
. Por padrão sete métodos são definidos nele:
- index() => Mostra uma lista de casos cadastrados
- create() => Cria novos casos usando um formulário
- store() => Cria novos casos no banco de dados
- show() => Mostra um casos específico
- edit() => Atualiza os dados dos casos usando um formulário
- update() => Atualiza os dados dos casos no banco
- destroy() => Remove um caso em particular
7. Configurando Controller
Edite o arquivo app/Http/Controllers/CoronaController.php
:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Corona;
class CoronaController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$coronacases = Corona::all();
return view('coronas.index', compact('coronacases'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('coronas.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'country_name' => 'required|max:255',
'symptoms' => 'required',
'cases' => 'required|numeric',
]);
$show = Corona::create($validatedData);
return redirect('/coronas')->with('success', 'Dados de Corona adicionado com sucesso!');
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$coronacase = Corona::findOrFail($id);
return view('coronas.show',compact('coronacase'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$coronacase = Corona::findOrFail($id);
return view('coronas.edit', compact('coronacase'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$validatedData = $request->validate([
'country_name' => 'required|max:255',
'symptoms' => 'required',
'cases' => 'required|numeric',
]);
Corona::whereId($id)->update($validatedData);
return redirect('/coronas')->with('success', 'Dados de Corona atualizado com sucesso!');
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$coronacase = Corona::findOrFail($id);
$coronacase->delete();
return redirect('/coronas')->with('success', 'Dados de Corona removido com sucesso!');
}
}
8. Configurando Rotas
Edite o arquivo routes/web.php
:
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::resource('coronas', 'CoronaController');
Já pode visualizar as novas rotas usando o comando:
php artisan route:list
Lista das novas rotas criadas:
Method | URI | Action | Route Name |
POST | coronas | store | coronas.store |
GET|HEAD | coronas | index | coronas.index |
GET|HEAD | coronas/create | create | coronas.create |
DELETE | coronas/{corona} | destroy | coronas.destroy |
PUT|PATCH | coronas/{corona} | update | coronas.update |
GET|HEAD | coronas/{corona} | show | coronas.show |
GET|HEAD | coronas/{corona}/edit | edit | coronas.edit |
9. Criando Views usando Blade Templates
Para cada rota GET, precisamos criar uma visualização.
Agora, criaremos as views em resources/views/coronas
:
- create.blade.php
- edit.blade.php
- index.blade.php
- layout.blade.php
- show.blade.php
Para ganhar tempo iremos criar todas de uma só vez usando o comando:
mkdir resources/views/coronas
touch resources/views/coronas/create.blade.php resources/views/coronas/edit.blade.php resources/views/coronas/index.blade.php resources/views/coronas/layout.blade.php resources/views/coronas/show.blade.php
10. Configurando o layout usando Bootstrap CDN
Edite o arquivo resources/views/coronas/layout.blade.php
:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title') - {{ config('app.name', 'i9W3b') }}</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<style>
.btn-group-sm>.btn, .btn-sm {
padding: .1rem .5rem;
font-size: .8rem;
line-height: 1.5;
border-radius: .2rem;
color: #fff !important;
}
body {
font-family: "Nunito", sans-serif;
font-size: 0.9rem;
background-color: #f8fafc;
}
</style>
@stack('css')
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'i9W3b') }}
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
@if (Route::has('logout'))
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }} <span class="caret"></span>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}" onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST"
style="display: none;">
@csrf
</form>
</div>
</li>
@endif
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
</main>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
@stack('js')
</body>
</html>
Agora é só configurar as views para criar, armazenar, visualizar e validar os dados no banco de dados MySQL
11. View Create (Cria novas entradas de dados no banco)
Esses dados serão gerados usando componentes Bootstrap Form e Card UI.
Edite o arquivo resources/views/coronas/create.blade.php
:
@extends('coronas.layout')
@section('title',__('Criar (Corona CRUD Laravel) - i9W3b'))
@push('css')
<style>
/* Personalizar layout*/
</style>
@endpush
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between w-100">
<span>@lang('Criar (Corona CRUD Laravel) - i9W3b')</span>
<a href="{{ url('coronas') }}" class="btn-info btn-sm">
<i class="fa fa-arrow-left"></i> @lang('Voltar')
</a>
</div>
</div>
<div class="card-body">
@if (session('success'))
<div class="alert alert-success" role="alert">
{{ session('success') }}
</div>
@endif
{!! Form::open(['action' =>'CoronaController@store', 'method' => 'POST'])!!}
<div class="form-group">
{!! Form::label(__('Nome do País:')) !!}
{!! Form::text("country_name", null ,["class"=>"form-control","required"=>"required"]) !!}
</div>
<div class="form-group">
{!! Form::label(__('Total de Casos:')) !!}
{!! Form::text("symptoms", null ,["id" => "symptoms", "class"=>"form-control mmss","required"=>"required"]) !!}
</div>
<div class="form-group">
{!! Form::label(__('Total de Mortes:')) !!}
{!! Form::text("cases", null ,["id" => "cases", "class"=>"form-control mmss","required"=>"required"]) !!}
</div>
<div class="well well-sm clearfix">
<button class="btn btn-success pull-right" title="@lang('Salvar')"
type="submit">@lang('Adicionar')</button>
</div>
{!! Form::close() !!}
</div>
</div>
</div>
</div>
</div>
@endsection
@push('js')
<script language='JavaScript'>
$(".mmss").focusout(function () {
var id = $(this).attr('id');
var vall = $(this).val();
var regex = /[^0-9]/gm;
const result = vall.replace(regex, ``);
$('#' + id).val(result);
});
</script>
@endpush

12. View Edit (Edita e Atualiza os dados)
Editar o arquivo resources/views/coronas/edit.blade.php
:
@extends('coronas.layout')
@section('title',__('Editar (Corona CRUD Laravel) - i9W3b'))
@push('css')
<style>
/* Personalizar layout*/
</style>
@endpush
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between w-100">
<span>@lang('Editar (Corona CRUD Laravel) - i9W3b')</span>
<a href="{{ url('coronas') }}" class="btn-info btn-sm">
<i class="fa fa-arrow-left"></i> @lang('Voltar')
</a>
</div>
</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
{!! Form::open(['action' => ['CoronaController@update',$coronacase->id], 'method' => 'PUT'])!!}
<div class="form-group">
{!! Form::label(__('Nome do País:')) !!}
{!! Form::text("country_name", $coronacase->country_name ,["class"=>"form-control","required"=>"required"]) !!}
</div>
<div class="form-group">
{!! Form::label(__('Total de Casos:')) !!}
{!! Form::text("symptoms", $coronacase->symptoms ,["id" => "symptoms", "class"=>"form-control mmss","required"=>"required"]) !!}
</div>
<div class="form-group">
{!! Form::label(__('Total de Mortes:')) !!}
{!! Form::text("cases", $coronacase->cases ,["id" => "cases", "class"=>"form-control mmss","required"=>"required"]) !!}
</div>
<div class="well well-sm clearfix">
<button class="btn btn-success pull-right" title="@lang('Salvar')"
type="submit">@lang('Adicionar')</button>
</div>
{!! Form::close() !!}
</div>
</div>
</div>
</div>
</div>
@endsection
@push('js')
<script language='JavaScript'>
$(".mmss").focusout(function () {
var id = $(this).attr('id');
var vall = $(this).val();
var regex = /[^0-9]/gm;
const result = vall.replace(regex, ``);
$('#' + id).val(result);
});
</script>
@endpush

13. View Index (Lista todos os cadastros do banco de dados)
Editar arquivo resources/views/coronas/index.blade.php
:
@extends('coronas.layout')
@section('title',__('Corona (CRUD Laravel) - i9W3b'))
@push('css')
<style>
/* Personalizar layout*/
</style>
@endpush
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between w-100">
<span>@lang('Corona (CRUD Laravel) - i9W3b')</span>
<a href="{{ url('coronas/create') }}" class="btn-primary btn-sm">
<i class="fa fa-plus"></i> @lang('Criar Novo')
</a>
</div>
</div>
<div class="card-body">
@if (session('success'))
<div class="alert alert-success" role="alert">
{{ session('success') }}
</div>
@endif
<table class="table table-bordered">
<thead>
<tr>
<td>ID</td>
<td>@lang('Nome do País')</td>
<td>@lang('Total de Casos')</td>
<td>@lang('Total de Mortes')</td>
<td colspan="3" class="text-center">@lang('Ações')</td>
</tr>
</thead>
<tbody>
@foreach($coronacases as $case)
<tr>
<td>{{$case->id}}</td>
<td>{{$case->country_name}}</td>
<td>{{number_format($case->symptoms,0,",",".")}}</td>
<td>{{number_format($case->cases,0,",",".")}}</td>
<td class="text-center p-0 align-middle" width="70">
<a href="{{ route('coronas.show', $case->id)}}"
class="btn btn-info btn-sm">@lang('Abrir')
</a>
</td>
<td class="text-center p-0 align-middle" width="70">
<a href="{{ route('coronas.edit', $case->id)}}"
class="btn btn-primary btn-sm">@lang('Editar')
</a>
</td>
<td class="text-center p-0 align-middle" width="70">
<form action="{{ route('coronas.destroy', $case->id)}}" method="post">
@csrf
@method('DELETE')
<button class="btn btn-danger btn-sm" type="submit">Delete</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('js')
<script>
// Script personalizado
</script>
@endpush

14. View Show (Mostra um cadastro específico)
Editar arquivo resources/views/coronas/show.blade.php
:
@extends('coronas.layout')
@section('title',__($coronacase->country_name . ': Corona CRUD Laravel - i9W3b'))
@push('css')
<style>
table{
font-family: Verdana,sans-serif;
border: 1px solid #ccc;
margin: 20px 0;
}
table th{
padding:10px;
font-weight: normal;
}
</style>
@endpush
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between w-100">
<span><span class="text-info">{{$coronacase->country_name}}</span>: (@lang('Corona CRUD Laravel')) - i9W3b</span>
<a href="{{ url('coronas') }}" class="btn-info btn-sm">
<i class="fa fa-arrow-left"></i> @lang('Voltar')
</a>
</div>
</div>
<div class="card-body">
@if (session('success'))
<div class="alert alert-success" role="alert">
{{ session('success') }}
</div>
@endif
<table class="w3-table-all notranslate" width="100%" border="1">
<tbody>
<tr>
<th align="left"><strong>ID:</strong></th>
<th align="left">{{$coronacase->id}}</th>
</tr>
<tr>
<th align="left"><strong>@lang('Nome do País')</strong>:</th>
<th align="left">{{$coronacase->country_name}}</th>
</tr>
<tr>
<th align="left"><strong>@lang('Total de Casos')</strong>:</th>
<th align="left">{{$coronacase->symptoms}}</th>
</tr>
<tr>
<th align="left"><strong>@lang('Total de Mortes')</strong>:</th>
<th align="left">{{$coronacase->cases}}</th>
</tr>
<tr>
<th align="left"><strong>@lang('Adicionado')</strong>:</th>
<th align="left">{{$coronacase->created_at}}</th>
</tr>
<tr>
<th align="left"><strong>@lang('Atualizado')</strong>:</th>
<th align="left">{{$coronacase->updated_at}}</th>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('js')
<script>
// Script personalizado
</script>
@endpush
Pronto!
Agora podemos iniciar executando:
php artisan serve
Acessar a rota /coronas/create
e começar a cadastrar os casos da pandemia no sistema:
http://127.0.0.1:8000/coronas/create
Ver os valores cadastrados:
http://127.0.0.1:8000/coronas
Repositório somente dos arquivos criados: https://github.com/i9w3b/tutorial-crud-files
Repositório do projeto: https://github.com/i9w3b/tutorial-crud-project
Comente abaixo se conseguiu seguir os passos e se tudo funcionou como deveria!
Caso tenha alguma sugestão de novas postagens também pode me contatar -> Falar com Marcelo Sena
Muito bom parabes
Obrigado João!
Até que enfim consegui criar o primeiro CRUD no Laravel, depois de vairias tentativas fracassadas kkk, obrigado o seu conteudo é bem organizado e didático.
muito top