crud-laravel

Como criar um CRUD usando Laravel (parte 2)

Nesta segunda parte do post de como criar um CRUD usando Laravel vamos criar o código responsável por remover e editar um equipamento da tabela (letras U e D do CRUD).

Route Model Binding

Começando pela operação de deletar, iremos criar uma rota e para isto alterar o arquivo routes\web.php incluindo em seu final o seguinte código:

Route::get('/equipamento/delete/{equipamento}', function (App\Equipamento $equipamento) {
	return view('equipamentos.destroy', ['eqp' => $equipamento]);
})->name('equipamento.delete');

A respeito desta nova rota cabe destacar que ela utiliza o recurso Route Model Binding presente no Laravel, pelo qual o parâmetro recebido pela rota, em vez de um valor simples como por exemplo um id, será um model do tipo equipamento.

Assim, todos os atributos e métodos do $equipamento estarão disponíveis para acesso no template do Blade que será retornado pela rota .

Para criar rotas do tipo Route Model Binding basta declarar que elas recebem um parâmetro do tipo Model, como no exemplo acima onde informamos que $equipamento deverá ser do tipo App\Equipamento.

Named route

No código acima usamos o método name para definir o nome da rota, ou seja, esta rota é uma named route ou rota nomeada, mais um recurso do Laravel que permite criar uma referência (nome) mais conveniente para geração de URL e redirecionamentos para rotas específicas.

Logo a seguir temos um exemplo deste uso, pois vamos alterar o arquivo resources\views\equipamentos\index.blade.php de forma a que ele inclua os links para a rota nomeada equipamento.delete criada acima.

Assim, inclua no código deste arquivo o trecho destacado abaixo na linha 8:

<td>{{ $equipamento->fabricante }}</td>
   <td>
    <ul class="list-inline">
      <li>
    	<a href="">Editar</a>
      </li>
      <li>
    	<a href="{{route('equipamento.delete', ['equipamento' => $equipamento])}}">Deletar</a>
      </li>
    </ul>
</td>




Formulário DELETE

Antes de efetivamente deletar o registro o aplicativo deverá exibir os respectivos dados e solicitar que o usuário confirme a exclusão do equipamento.

Para isto vamos criar agora o form que implementa estas funcionalidades.

Crie o arquivo resources\views\equipamentos\destroy.blade.php e digite o seguinte código:

@extends('layouts.app')
@section('content')
<div class="container">
  <div class="row">
    <h3>Deletar Equipamento</h3>
    <form action={{route('equipamento.destroy', ['equipamento' => $eqp->id])}} method="post">
    @csrf
    @method('DELETE')
    <input type="hidden" id="redirect_to" name="redirect_to" value={{URL::previous()}}>
    <div>
	<label for="tipo">Tipo Equipamento</label>
	<input type="text" id="tipo" name="tipo" value="{{$eqp->tipo}}" disabled>
    </div>
    <div>
	<label for="modelo">Modelo Equipamento</label>
	<input type="text" id="modelo" name="modelo" value="{{$eqp->modelo}}" disabled>
    </div>
    <div>
	<label for="fabricante">Fabricante Equipamento</label>
	<input type="text" id="fabricante" name="fabricante" value="{{$eqp->fabricante}}" disabled>
    </div>
    <div class="alert alert-danger" role="alert">Esta operação não poderá ser desfeita! Confirma a exclusão do equipamento?</div>
    <div class="form-group">
	  <input type="submit" name="delete_eqp" value="Deletar equipamento">
	  <input type="submit" name="cancel" value="Cancelar">
      </div>
  </div>
  </form>
</div>
@endsection

Examinando o código acima podemos constatar que se trata de um formulário HTML. Aqui cabe lembrar um pouco do funcionamento dos formulários, estes são usados para receber as entradas/inputs de usuários através de diversos elementos como <input>, <select>, <textarea>, <button>, <option> e outros.

Após o preenchimento dos campos o usuário deve acionar um botão do tipo submit, normalmente intitulado Enviar, que irá submeter o formulário em questão.

No código que estamos examinando foram incluídos dois botões do tipo submit, veja as linhas 24 e 25, um deles para confirma a exclusão do equipamento e o outro para cancelar esta operação.

Os dados serão recebidos e tratados pela a página / script que estiver definida como o atributo action do formulário. No código acima isto é feito na linha 6.

Para determinar qual o método HTTP que será acionado o formulário possui um atributo method. Assim, caso o atributo method seja igual a GET os dados do formulário serão enviados como variáveis em uma URL, ou, caso seja usado method igual a POST os dados irão constituir uma transação post HTTP.

Método DELETE

Na figura acima, obtida pelo comando php artisan route:list, podemos ver as rotas definidas em nosso CRUD, observe que na coluna Method estão listados os métodos http que correspondem a cada uma das rotas.

O padrão http define vários métodos, também chamados de verbos http, são eles: POST, GET, HEAD, PUT, PATCH e DELETE, entretanto, os formulários HTML somente dão suporte aos verbos POST e GET.

Por este motivo quando utilizar uma rota do tipo PUT, PATCH ou DELETE como a action de seus formulários você precisará incluir no formulário um campo escondido com o nome de _method.

O Laravel utilizará o valor deste campo _method para identificar qual o método da requisição http e desta forma acionar a rota correspondente.

Assim, no formulário cujo código estamos examinando, na linha 8, foi usada a diretiva @method(‘DELETE’) do Blade para gerar este campo _method.

Da mesma forma que a diretiva o @csrf , nas versões mais novas do Laravel você deve usar a diretiva @method(‘DELETE’) do Blade para gerar um campo _method.

Nas mais antigas era usado o campo {{ method_field(‘DELETE’) }}.

Assim, caso você esteja trabalhando em uma versão anterior do Laravel, ou se depare com código escrito em versões anteriores, já sabe que caso tenha problemas com o @method(‘DELETE’) basta substitui-lo pelo {{method_field(‘DELETE’)}}.




URL prévia

Em seguida, na linha 9 vemos que o código cria um outro campo escondido que serve para armazenar a rota atual de forma a ser possível retornar a tela anterior.

Isto é feito pelo trecho de código abaixo:

<input type="hidden" id="redirect_to" name="redirect_to" value={{URL::previous()}}>

O código usa a facade (uma facade no Laravel representa uma interface estática para acessar uma classe de serviços) URL para obter o endereço da página anterior e armazenar no campo redirect_to.

Este valor será usado posteriormente para retornar à página de onde o formulário foi chamado.

Incluímos este código com o objetivo de possibilitar que a exclusão de equipamentos seja chamada de outros locais de nosso aplicativo e não somente da tela onde estão listados os equipamentos.

Dados do model

Conforme mencionamos antes a rota equipamento/delete{equipamento}, que dá acesso ao formulário que estamos examinando, utiliza o Route Model Binding, de forma que é repassado um objeto do tipo Equipamento Model para o template do Blade.

Por este motivo é possível acessar todos os atributos do equipamento passado como parâmetro.

Estes atributos são usados para preencher os campos do formulário (linhas 11 a 21) os quais, como este é um formulário somente de leitura, possuem o atributo disabled que faz com que não seja possível editar seus valores.

Após os dados do equipamento, na linha 22 o código exibe uma mensagem de alerta informando que a operação não poderá ser desfeita e, finalmente, nas linhas 24 e 25 cria os botões que disparam a ação do formulário.

Botões submit

Nosso formulário possui dois botões do tipo submit, um com o nome de delete_eqp e o outro com o nome cancel.

Estes atributos de nome serão usados no controller para identificar qual botão foi pressionado e agir conforme a escolha do usuário. Na tela abaixo está ilustrado o formulário que será exibido quando o código for interpretado.

Definindo o destroy

Prosseguindo, vamos agora criar o código que irá efetivar a exclusão do equipamento. Para isto vamos alterar o método destroy no arquivo app\Http\Controllers\EquipamentosController.php para que fique da seguinte forma:

public function destroy(Equipamento $equipamento, Request $request))
    {
        //
        if (! $request->has('cancel') ){
            $equipamento->delete();
            \Session::flash('message', 'Equipamento excluído com sucesso !');
        }
        else
        { 
            $request->session()->flash('message', 'Operação cancelada pelo usuário'); 
        }
        return redirect()->route('equipamento.index'); 
    }

Analisando o código podemos ver que foi feita uma alteração na declaração da function destroy para que agora ela receba como parâmetro um objeto model do tipo Equipamento. Isto é possível graças ao recurso Route Model Bind presente no Laravel e que já foi mencionado antes.

Assim este método passará a receber dois parâmetros: um model Equipamento e uma Request, e terá acesso aos dados de ambos.

Com relação à $request, podemos ver que o código utiliza o seu método has para saber se NÃO foi pressionado o botão cancel. Ou seja, se o usuário confirmou a operação e pressionou o botão Deletar equipamento.

Neste caso o código irá utilizar o método delete do $equipamento que recebeu como parâmetro e remover o mesmo. E, após isto, usar a facade Session para armazenar uma mensagem de operação bem sucedida que será exibida ao usuário.

No caso contrário, ou seja, se o botão cancel foi pressionado, o código somente irá criar a mensagem informando que a operação foi cancelada pelo usuário.




Facade Session

Em virtude de o HTTP ser um protocolo stateless, ou seja, que não guarda informação de estado entre as várias requisições do usuário, o Laravel disponibiliza a facade Session que permite que sejam armazenadas informações que serão compartilhadas entre as múltiplas requisições http.

Ajustando as configurações de driver no Laravel, estas informações podem ser armazenadas em arquivos de texto, em algum banco de dados ou em cache.

Sendo o padrão a utilização do driver file que as armazena em arquivos de texto.

Para saber mais pode acessar a página da documentação do Laravel no link abaixo:

https://laravel.com/docs/7.x/session

Editar

Passemos agora para a letra U de nosso CRUD, o update ou edit, e a primeira coisa a fazer é definir uma rota, assim altere o arquivo routes\web.php incluindo no final este trecho de código:

Route::get('/equipamento/edit/{equipamento}', function (App\Equipamento $equipamento) {
	return view('equipamentos.edit', ['eqp' => $equipamento]);
})->name('equipamento.edit');

Definimos uma rota com o Route Model Bindig do Laravel que retorna uma view (template do Blade) para a qual é passado como parâmetro uma model do tipo Equipamento.

Esta definição de rota é muito semelhante a que foi feita anteriormente para a operação de delete de forma que não necessita de maiores explicações.

Da mesma forma que fizemos para a operação DELETE iremos agora alterar o arquivo resources\views\equipamentos\index.blade.php de forma a que ele inclua os links para a rota equipamento.edit criada acima. Assim, insira no código deste arquivo o trecho que está destacado na linha 10 abaixo para que fique da forma seguinte:

@foreach($equipamentos as $equipamento)
    <tr>
    	<td>{{ $equipamento->id }}</td>
    	<td>{{ $equipamento->tipo }}</td>
    	<td>{{ $equipamento->modelo }}</td>
	<td>{{ $equipamento->fabricante }}</td>
    	<td>
    	  <ul class="list-inline">
    	    <li>
    	      <a href="{{route('equipamento.edit', ['equipamento' => $equipamento])}}">Editar</a>
    	    </li>
    	    <li>
    	      <a href="{{route('equipamento.delete', ['equipamento' => $equipamento])}}">Deletar</a>
	        </li>
    	  </ul>
    	</td>
    </tr>
@endforeach

Form de Edição

De forma semelhante ao que fizemos para o Delete vamos agora codificar um formulário para a função de edição.

Para isto você deverá criar o arquivo resources\views\equipamentos\edit.blade.php e nele digitar o código abaixo:

@extends('layouts.app')

@section('content')
<div class="container">
	<div class="row">
        <h3>Editar Equipamento</h3>
    <form action={{route('equipamento.update', ['equipamento' => $eqp])}} method="post">
        @csrf
        @method('PUT')
        <input type="hidden" id="redirect_to" name="redirect_to" value={{URL::previous()}}>
        <input type="hidden" id="id" name="id" value={{$eqp->id}}>
        <div>
            <label for="tipo">Tipo Equipamento</label>
            <input type="text" id="tipo" name="tipo" value="{{$eqp->tipo}}">
        </div>
        <div>
            <label for="modelo">Modelo Equipamento</label>
            <input type="text" id="modelo" name="modelo" value="{{$eqp->modelo}}">
        </div>
        <div>
            <label for="fabricante">Fabricante Equipamento</label>
            <input type="text" id="fabricante" name="fabricante" value="{{$eqp->fabricante}}">
        </div>
            <div class="form-group">
                <input type="submit" name="save_eqp" value="Atualizar equipamento">
                <input type="submit" name="cancel" value="Cancelar">
            </div>
        </div>
	</form>
</div>
@endsection

Se você examinar este código com atenção verá que ele é muito parecido com o formulário que criamos antes para a opção de deletar.

Por enquanto você não deve se preocupar com esta repetição de código, pois em uma ocasião posterior iremos refatorar o formulário.

No momento vamos nos concentrar nas diferenças entre os dois formulários e, mais tarde quando fizermos a refatoração, focaremos nas semelhanças.

Iniciando as diferenças vemos na linha 7 o título e a rota que será a action do formulário, ou seja, a url que processará a requisição enviada por ele. Nenhuma novidade aqui, pois já tratamos deste assunto no início do texto.

Método PUT

Uma outra diferença que devemos destacar é o método PUT conforme a linha 9. Na explicação do formulário delete vimos que os forms html não dão suporte a certos verbos http, e que para contornar esta limitação o Laravel possibilita a criação de campos escondidos que definem o método e a identificação da rota.

Enquanto no formulário de delete o campo criado era o DELETE, neste formulário de edição o campo será o PUT.

Assim, no código que estamos examinado temos a diretiva @method(‘PUT’) do Blade que é responsável por criar este campo correspondente ao método.

Uma outra modificação foi feita nos campos de input e retirado o atributo disabled, o que permite agora que eles recebam as alterações.

Finalmente, conforme a linha 25, o label/value e o nome do primeiro botão de submit foram alterados para, respectivamente, Atualizar equipamento e save_eqp.

Na figura abaixo vemos como deverá se parecer o formulário de edição:

Após alterar os dados que desejar o usuário poderá clicar no botão Atualizar Equipamento para que seja acionado o método update e estes sejam salvos no banco de dados.

Definindo o update

Para finalizar a parte de edição de nosso CRUD falta codificar o método update do controller, para isto faça as alterações abaixo no arquivo app\Http\Controllers\EquipamentosController.php.

public function update(Equipamento $equipamento, Request $request)
    {
        if (! $request->has('cancel') ){
            $equipamento->tipo = $request->input('tipo');
            $equipamento->modelo = $request->input('modelo');
            $equipamento->fabricante = $request->input('fabricante');
            $equipamento->update();
            \Session::flash('message', 'Equipamento atualizado com sucesso !');
        }
        else
        { 
            $request->session()->flash('message', 'Operação cancelada pelo usuário'); 
        }
        return redirect()->route('equipamento.index'); 
    }

Examinando o código pode ver que a primeira alteração a ser feita é na definição do método, este agora passará a receber dois parâmetros: o objeto $equipamento e a $request.

Em seguida, de forma semelhante ao destroy, é verificado se NÃO foi pressionado o botão Cancelar e, neste caso, os atributos do $equipamento recebem os valores atualizados e que foram informados pelos usuários nos elementos de input correspondentes ao formulário anterior.

A atualização é feita chamando-se o método update do objeto $equipamento.

Prosseguindo, é utilizada a facade Session para gerar uma mensagem informando aos usuários que a atualização foi bem sucedida.

Melhorias

Este post conclui a criação de um CRUD que executa as operações básicas, porém necessita ser melhorado.

Precisamos ainda implementar a validação dos dados recebidos pelos formulários.

Além disso, podemos melhorar o código refatorando para eliminar repetições.

Para evitar que este fique muito longo, faremos isto em um outro post. Até lá!

Leia o próximo post da série Como criar um CRUD Laravel (conclusão) e veja como:

  • Usar seed e factory para popular o banco de dados
  • Implementar a paginação usando Bootstrap com Laravel 8
  • Validar os dados de entrada do formulário
  • Refatorar e unificar os formulários

Leia também

Como criar um CRUD usando Laravel
Laravel e banco de dados SQLite
eBook chatbot usando Laravel Botman e Dialogflow