Thiago Cantero

Tecnologia e Entretenimento

JQuery UILaravelMySQLPHP

Criando um Calendário com persistência, AJAX e com Laravel

Olá, mundo!
Tudo bem?

Hoje venho trazer um outro exemplo com a simplicidade de integração com componentes de bibliotecas Javascript com Laravel.

Vamos ao trabalho//

Vamos criar um novo projeto com Laravel. Estou usando a Versão 8.1 do PHP e o Laravel 9, no entanto funciona com a versão 7.4 do PHP e o Laravel 8.

composer create-project laravel/laravel laravel_cal

Com o projeto criado, vamos a configuração inicial de nosso arquivo .env na pasta raiz do projeto:
.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_cal
DB_USERNAME=<usuário>
DB_PASSWORD=<senha>

Agora vamos criar na pasta de nosso projeto, nossa migration:

php artisan make:migration create_eventos_table

 

database/migrations/2022_12_05_132037_create_eventos_table.php

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('eventos', function (Blueprint $table) {
            $table->id();
            $table->string('titulo');
            $table->date('inicio');
            $table->date('fim');
            $table->timestamps();
        });
    }

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

 

Vamos criar nosso banco de dados:

create database laravel_cal;

Pronto, agora vamos rodar nossa migration:

php artisan migrate

criaremos nossa classe model:

php artisan make:model Evento

 

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Evento extends Model
{
    use HasFactory;


    protected $fillable = [
        'titulo', 'inicio', 'fim'
    ];
}

Agora criaremos nosso controller, que terá dois métodos: um que pegará as informações persistentes no banco, e outro que fará requisições assíncronas, utilizando JQuery e o FullCalendar, para que realize inserção, alteração e exclusão de maneira reativa:

php artisan make:controller CalendarioController

 

CalendarioController.php

<?php

namespace App\Http\Controllers;

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

class CalendarioController extends Controller
{
    public function index(Request $request)
    {
  
        if($request->ajax()) {
       
             $data = Evento::whereDate('inicio', '>=', $request->inicio)
                       ->whereDate('fim',   '<=', $request->fim)
                       ->get(['id', 'titulo', 'inicio', 'fim']);
  
             return response()->json($data);
        }
  
        return view('calendario');
    }
 
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function ajax(Request $request)
    {
 
        switch ($request->type) {
           case 'add':
              $evento = Evento::create([
                  'titulo' => $request->titulo,
                  'inicio' => $request->inicio,
                  'fim' => $request->fim,
              ]);
 
              return response()->json($evento);
             break;
  
           case 'update':
              $evento = Evento::find($request->id)->update([
                  'titulo' => $request->titulo,
                  'inicio' => $request->inicio,
                  'fim' => $request->fim,
              ]);
 
              return response()->json($evento);
             break;
  
           case 'delete':
              $evento = Evento::find($request->id)->delete();
  
              return response()->json($evento);
             break;
             
           default:
             # 
             break;
        }
    }
}

Como podemos observar nosso Controller, no método index() que já faz requisições ajax, através da injeção de dependência Request do Laravel, já no método ajax() temos a condição de cada função de adição, remoção, atualização que faremos a chamada em nossa view, através do JQuery.

Criaremos agora nossa view, resources/view/calendario.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>Calendário com Laravel</title>
    <meta name="csrf-token" content="{{ csrf_token() }}">
  
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/locale/pt-br.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" />
</head>
<body>
   
<div class="container">
    <h1>Calendário com Laravel e JQuery</h1>
    <div id='calendar'></div>
</div>
   
<script>



$(document).ready(function () {

    
var SITEURL = "{{ url('/') }}";



$.ajaxSetup({
    headers: {
    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
  
var calendar = $('#calendar').fullCalendar({
                    editable: true,
                    events: SITEURL + "/calendario",
                    displayEventTime: false,
                    editable: true,
                    eventRender: function (event, element, view) {
                        if (event.allDay === 'true') {
                                event.allDay = true;
                        } else {
                                event.allDay = false;
                        }
                    },
                    selectable: true,
                    selectHelper: true,
                    select: function (start, end, allDay) {
                        var title = prompt('Título do Evento:');
                        if (title) {
                            var start = $.fullCalendar.formatDate(start, "Y-MM-DD");
                            var end = $.fullCalendar.formatDate(end, "Y-MM-DD");
                            $.ajax({
                                url: SITEURL + "/calendarioAjax",
                                data: {
                                    title: title,
                                    start: start,
                                    end: end,
                                    type: 'add'
                                },
                                type: "POST",
                                success: function (data) {
                                    displayMessage("Evento criado com Sucesso");
  
                                    calendar.fullCalendar('renderEvent',
                                        {
                                            id: data.id,
                                            title: title,
                                            start: start,
                                            end: end,
                                            allDay: allDay
                                        },true);
  
                                    calendar.fullCalendar('unselect');
                                }
                            });
                        }
                    },
                    eventDrop: function (event, delta) {
                        var start = $.fullCalendar.formatDate(event.start, "Y-MM-DD");
                        var end = $.fullCalendar.formatDate(event.end, "Y-MM-DD");
  
                        $.ajax({
                            url: SITEURL + '/calendarioAjax',
                            data: {
                                title: event.title,
                                start: start,
                                end: end,
                                id: event.id,
                                type: 'update'
                            },
                            type: "POST",
                            success: function (response) {
                                displayMessage("Evento Atualizado com Sucesso!");
                            }
                        });
                    },
                    eventClick: function (event) {
                        var deleteMsg = confirm("Você deseja apagar este evento?");
                        if (deleteMsg) {
                            $.ajax({
                                type: "POST",
                                url: SITEURL + '/calendarioAjax',
                                data: {
                                        id: event.id,
                                        type: 'delete'
                                },
                                success: function (response) {
                                    calendar.fullCalendar('removeEvents', event.id);
                                    displayMessage("Evento Apagado com Sucesso");
                                }
                            });
                        }
                    }
 
                });
 
});
 
function displayMessage(message) {
    toastr.success(message, 'Evento');
} 


</script>
  
</body>
</html>

 

routes/web.php

Route::get('calendario', [CalendarioController::class, 'index']);
Route::post('calendarioAjax', [CalendarioController::class, 'ajax']);

agora vamos rodar a aplicação:

php artisan serve

 

A biblioteca Fullcalendar tem uma ampla documentação para se customizar conforme a necessidade de seu negócio.

Código fonte no Github.

 

Estudem seus homens com tanto cuidado quanto um cirurgião
estuda um caso difícil. E, quando tiverem certeza do diagnóstico,
apliquem o remédio. Lembrem-se de que vocês aplicam o remédio
para efetuar uma cura, não para ver a vítima contorcer-se. Pode ser
necessário cortar fundo, mas, quando estiverem satisfeitos com o
diagnóstico, não se desviem do objetivo por alguma falsa simpatia
pelo paciente. – O Manuscrito Original – Napoleon Hill