Thiago Cantero

Tecnologia e Entretenimento

Arquitetura de SoftwareDesenvolvimento WebJQuery UILaravelObserverPadrões de ProjetoPHP

Laravel – Exemplo prático de um projeto com AJAX com JQuery UI

Olá, mundo!

Laravel é um dos projetos mais bem estabelecidos no mundo dos Frameworks PHP, obviamente como o Symfony e o Zend (Atual Laminas), e não para tanto. Ele, além de ser muito bem documentado, possui um ecossistema complexo com uma gama bem abrangente para aplicações de pequeno, médio e grande porte.

A facilidade de integração com os principais Bancos de Dados relacionais, aliado com a ORM Eloquent (se tiver dúvidas sobre ORM) faço uma breve apresentação sobre ele e seus principais padrões aqui e aqui.

Seu ecossistema é muito rico, ofertando muitas possibilidades e facilidades de implementação, dentre os mais variados aspectos, como um CLI muito rico para aumentar ainda mais a produtividade de criação de classes de Models, Requests, Commands, dentre outras infinidades, inclusive podendo gerar um comando próprio a sua demanda. Como tenho feito há algumas semanas, com postagens sobre o Laravel, e caso queira entender melhor o funcionamento do Framework, recomendo este artigo aqui.

Neste exemplo iremos fazer uma busca, e autocompletar a pesquisa, para isso utilizaremos em nossa View, a biblioteca JQuery UI. Vão me falar: “Ain, JQuery?!”. Eu respondo, sim! JQuery, ele está em 74% dos  10 mil sites mais visitados do mundo , pare de ser tão imediatista e sem fundamento para criticar algo que não conheça!

E mesmo assim irá dizer: “Ain, eu uso ReactJS, Angular”. Eu respondo que são boas ferramentas de frontend, mas o JQuery também dá conta do recado! Então, relaxe e 12×8! ; )

O Padrão Observer

Vamos entender a “mágica” por trás da web 2.0 ou nos dias atuais, a web reativa. Perai, isso na Web, no entanto no Desktop já havia a reatividade, um grande exemplo são as planilhas de Excel! Criam-se muitas nomenclaturas para algo que já era consolidado, isto é o mercado!Mas não vamos nos apegar à discussão, e sim vamos ao ponto que interessa, afinal como tudo isso funciona?

Bom, se por ventura você já leu o famoso livro “Padrões de Projetos: Soluções Reutilizáveis  de Software Orientados a Objetos“, o famoso Gang of Four,recomendo a leitura, nele é encontrado o Padrão “Observer“. Vejamos como este padrão tem em sua forma.

“Um efeito colateral comum resultante do particionamento de um sistema em uma
coleção de classes cooperantes é a necessidade de manter a consistência entre objetos
relacionados. Você não deseja obter consistência tornando as classes fortemente
acopladas, porque isso reduz a sua reusabilidade.
Por exemplo, muitos toolkits para construção de interfaces gráficas de usuário
separam os aspectos de apresentação da interface do usuário dos dados da aplicação
subjacente [KP88,LVC89,P+88, WGM88]. As classes que definem dados da aplicação
e da apresentação podem ser reutilizadas independentemente. Elas também podem
trabalhar em conjunto. Tanto um objeto planilha como um objeto gráfico de barras
podem ilustrar informações do mesmo objeto de aplicação usando diferentes apresentações. A planilha e o gráfico de barras não têm conhecimento um do outro, desta
forma permitindo reutilizar somente o objeto de que você necessita. Porém, elas se
comportam como se conhecessem. Quando o usuário muda a informação na planilha,
o gráfico de barras reflete as mudanças imediatamente, e vice-versa. ” -Padrões de Projeto: Soluções reutilizáveis de software orientado a objetos, pág. 274, Editora Bookman 2008.

No livro exemplifica através do exemplo supracitado de uma planilha, em que o comportamento de um gráfico se altera, ao imputar um outro valor condizente ao eixo X ou Y. Inclusive o Observer está no rol dos Padrões Comportamentais, reitero a lembrança de se aprofundar nos estudos! ; )

Vejamos agora a estrutura de um diagrama de um padrão Observer, aplicado ao nosso exemplo:

No diagrama acima, o usuário faz uma requisição, no próprio formulário haverá uma maneira de executar um evento que disparará a consulta ao banco de dados, ele armazenará em um array, em nosso Controller, posteriormente, na camada de frontend, ele também terá esta coleção em de forma assícrona, possibilitando a alteração do comportamento, neste caso, nos trazendo parte do nome do cliente como  resposta e, no outro formulário, nos trará o email do cliente.

 

\\ Vamos ao projeto prático

Bom, vamos ao que interessa, vamos ao código.

Antes de mais nada, precisamos criar uma nova aplicação, neste exemplo faremos uma aplicação com chamada assíncrona com JQuery UI.

Damos o início com a criação de nossa aplicação Laravel.

composer create-project laravel/laravel laravel_jquery

Já de início, vamos configurar nosso ambiente para acesso ao banco de dados no arquivo raiz do projeto .env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_jquery
DB_USERNAME=root
DB_PASSWORD=<senha do banco de dados>

agora vamos criar nosso banco de dados:

CREATE database laravel_jquery;;

com o banco devidamente criado, vamos em nossa linha de comando e vamos criar nossa tabela de clientes:

php artisan make:migration criar_tabela_clientes

Vamos alterar nossa migration que foi gerada na pasta database/migrations/2022_07_08_230012_criar_tabela_clientes.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CriarTabelaClientes extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('clientes', function (Blueprint $table) {
            $table->id();
            $table->string('nome');
            $table->integer('telefone');
            $table->string('email');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        schema::dropIfExists('clientes');
    }
}

Agora vamos criar nossa classe Model

php artisan make:model Cliente

Façamos a alteração da nossa Model Clientes app/Models/Cliente.php

<?php

namespace App\Models;


use Illuminate\Database\Eloquent\Model;

class Cliente extends Model
{
    protected $table = 'clientes';

    protected $fillable = ['nome, telefone, email'];
    
}

Vamos alimentar com uma seeder nossa tabela clientes:

php artisan make:seeder ClienteSeeder

Alteramos o arquivo database/seeders/ClienteSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Cliente;

class ClienteSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
    $clientes = [ ["nome"     => "Thiago Cantero",
                  "telefone" => "11929292",
                  "email"    => "thiagocantero@gmail.com"],
                  ["nome"     => "Yoshi",
                  "telefone" => "2222222",
                  "email"    => "yoshi@mariobros.com"],
                  ["nome"     => "Elephant",
                  "telefone" => "0000222",
                  "email"    => "elephant@phpelephant.com"],
                  ["nome"     => "Sonci",
                  "telefone" => "2323232",
                  "email"    => "sonic@megadrive.com"],
    ];
            foreach ($clientes as $key => $value){
                Cliente::create($value);
            }
    }
}

Agora rodamos nossa seeder.

php artisan db:seed --class:ClienteSeeder

Agora todos os registros encontram-se em nossa tabela.

Com a estrutura de nossa aplicação feita, neste próximo passo devemos criar nosso Controller que irá fazer o controle de acesso a nossa camada de banco de dados (obtidos da rota), juntamente com uma espécie de API para retornar dados para o frontend.

php artisan make:controller ClientesController

Colocamos os seguintes métodos em nosso Controller app/Http/Controllers/ClientesController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Cliente;

class ClientesController extends Controller
{
    public function index(){
        return view('index');
    }

    public function getClientes(Request $request){
        
        //Instancia a variável busca com a injenção de dependência Request do laravel
        $busca = $request->busca;

        //Se a busca estiver vazia, apenas carrega a consulta de select pelo nome e email
        if($busca == ""){
            $clientes = Cliente::orderby('nome', 'asc')->select('nome', 'email')->limit(5)->get();
        }else{//senão ordena com a condição do nome like para passar para o javascript
            $clientes = Cliente::orderby('nome', 'asc')->select('nome', 'email')->where('nome', 'like', '%')->limit(5)->get();
        }
        //a resposta será armazenada no array com os valores dos campos "email" e "nome" da tablea clientes
        $resposta = array();
        foreach($clientes as $cliente){
            $resposta[] = array("value"=>$cliente->email,"label"=>$cliente->nome);
        }
        //retorna com a função response() helper do Laravel em json toda a array da consulta
        return response()->json($resposta);
    }
}

Façamos a alteração no arquivo de rotas routes/web.php

<?php

use App\Http\Controllers\ClientesController;
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('/', [ClientesController::class, 'index']);
Route::post('getClientes', [ClientesController::class, 'getClientes'])->name('getClientes');

Por fim vamos criar nossa view com em resources/views/index.blade.php

<!DOCTYPE html>
<html>
<head>
   <title>Observer Pattern com JQuery UI e Laravel</title>

   <!-- Meta -->
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <meta charset="utf-8">
   <meta name="csrf-token" content="{{ csrf_token() }}">

   <!-- CSS -->
   <!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
   <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">

   <!-- Script -->
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
   <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

</head>
<body>
    <div class="row">
        <div class="col-12">
    
    <form>
        <!-- Aqui define o campo nome para a pesquisa de autocompletar -->
        <div class="form-group">
          <label for="exampleInputEmail1">Cliente</label>
         <input type="email" class="form-control" id="busca_cliente" aria-describedby="emailHelp" placeholder="Insira o Nome do Cliente">
        <div>
        <!-- Aqui retorna o email do cliente pesquisado -->
        <div class="form-group">
            <label for="exampleInputEmail1">Email</label>
            <input type="email" class="form-control" id="email" aria-describedby="emailHelp" placeholder="Aqui vai aparecer o email do Cliente">
                      
          </div>
        </div>      
    </div>
</div>

   <!-- Script -->
   <script type="text/javascript">

   // CSRF Token
   var CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content');
   $(document).ready(function(){

     $( "#busca_cliente" ).autocomplete({
        source: function( request, response ) {
           // Armazena a data, obtém a rota do método getClientes do ClientesController, com o método post no formato json
           $.ajax({
             url:"{{route('getClientes')}}",
             type: 'post',
             dataType: "json",
             data: {
                _token: CSRF_TOKEN,
                search: request.term
             },
             success: function( data ) {
                response( data );
             }
           });
        },
        select: function (event, ui) {
          // Define a Seleção
          $('#busca_cliente').val(ui.item.label); // demonstra o cliente pesquisado
          $('#email').val(ui.item.value); // demonstra o email do cliente no formulário
          return false;
        }
     });

   });
   </script>
</body>
</html>

Agora vamos testar a aplicação.

php artisan serve

Veja a aplicação rodando

Espero ter ajudado, como sempre reforço que se aprofundem nos estudos, o livro citado aqui é um grande referencial para seu sucesso.

Código fonte no github.

Ter grande conhecimento não é a mesma coisa que ser inteligente; inteligência não é apenas informação, mas também critério, o modo como a informação é coordenada e utilizada.