En esta ocasión se crea un proyecto en Laravel 11 para implementar el CRUD (Crear, Leer, Actualizar y Borrar) necesario para trabajar con el plugins javascript de FullCalendar.
¿Que necesitamos?
Una vez que ya tengas tu proyecto laravel 11 creado y abierto en tu editor de codigo favorito. Pongamos manos a la obra
Paso 1. Migration
Creamos una nueva migración donde se declara la tabla «events», en la misma se registraran todos los eventos del fullcalendar.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('events', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->date('start');
$table->date('end');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('events');
}
};
Se realiza la migración con el comando:
php artisan migrate:refresh
Paso 2. Model
A continuación se crea el modelo «Event»
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
use HasFactory;
protected $fillable = [
'title',
'start',
'end'
];
}
Paso 3. Services
Se crea una clase Service con el nombre «FullCalendarService.php», en el mismo se declaran las funciones necesarias para el CRUD.
<?php
namespace App\Services;
use Illuminate\Http\Request;
use App\Models\Event;
class FullCalendarService
{
public function events(Request $request)
{
$data = Event::whereDate('start', '>=', $request->start)
->whereDate('end', '<=', $request->end)
->get(['id', 'title', 'start', 'end']);
return response()->json($data);
}
public function add(Request $request){
$event = Event::create([
'title' => $request->title,
'start' => $request->start,
'end' => $request->end,
]);
return response()->json($event);
}
public function update(Request $request){
$event = Event::find($request->id)->update([
'title' => $request->title,
'start' => $request->start,
'end' => $request->end,
]);
return response()->json($event);
}
public function destroy($id){
$event = Event::find($id)->delete();
return response()->json($event);
}
}
Paso 4. Controller
Se requiere una clase controller bajo el nombre de «FullCalendarController.php», en el mismo se inyectara el Service creado en el paso 3 y se declaran las funciones respectivas para el CRUD.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\FullCalendarService;
use Illuminate\Http\JsonResponse;
class FullCalendarController extends Controller
{
protected $fullCalendarService;
public function __construct(FullCalendarService $fullCalendarService)
{
$this->fullCalendarService = $fullCalendarService;
}
public function index()
{
return view('fullcalendar.index');
}
public function events(Request $request)
{
return $this->fullCalendarService->events($request);
}
public function add(Request $request): JsonResponse
{
return $this->fullCalendarService->add($request);
}
public function update(Request $request): JsonResponse
{
return $this->fullCalendarService->update($request);
}
public function destroy(Request $request)
{
return $this->fullCalendarService->destroy($request->id);
}
}
Paso 5. View
Ya finalizando se crea una vista index.blade.php en la ruta «views/fullcalendar/».
<!DOCTYPE html>
<html>
<head>
<title>CRUD Fullcalendar - Laravel 11 (https://www.jc-mouse.net/)</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css' rel='stylesheet'>
<link href='https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css' rel='stylesheet'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/index.global.min.js"></script>
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/core@6.1.15/locales-all.global.min.js'></script>
</head>
<body>
<div class="container">
<div class="card">
<div class="card-body">
<div id='calendar'></div>
</div>
</div>
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prevYear,prev,next,nextYear today'
, center: 'title'
, right: 'dayGridMonth,dayGridWeek,dayGridDay'
}
, navLinks: true
, editable: true
, displayEventTime: false
, selectable: true
, locale: 'es'
, events: "{{ route('fullcalendar.events') }}",
/** -------------------------------------------------------------
* creacion de eventos
*/
dateClick: function(info) {
var title = prompt('Nuevo evento:');
if (title) {
var start = moment(info.dateStr).format('Y-MM-DD');
var end = moment(info.dateStr).format('Y-MM-DD');
$.ajax({
url: "{{ route('fullcalendar.events.add') }}"
, data: {
_token: $('meta[name="csrf-token"]').attr('content')
, title: title
, start: start
, end: end
}
, type: "POST"
, success: function(data) {
calendar.addEvent({
id: data.id
, title: title
, start: end
, allDay: false
});
calendar.render();
}
});
}
},
/** -------------------------------------------------------------
* Eliminación de eventos
*/
eventClick: function(info) {
var deleteMsg = confirm("¿Realmente quieres eliminar este evento?");
if (deleteMsg) {
$.ajax({
type: "DELETE"
, url: "{{ route('fullcalendar.events.destroy') }}"
, data: {
_token: $('meta[name="csrf-token"]').attr('content')
, id: info.event.id
, }
, success: function(response) {
info.event.remove();
}
});
}
},
/** -------------------------------------------------------------
* Actualización de eventos
*/
eventDrop: function(info) {
var start = moment(info.event.start).format('Y-MM-DD');
var end = moment(info.event.start).format('Y-MM-DD');
$.ajax({
url: "{{ route('fullcalendar.events.update') }}"
, data: {
_token: $('meta[name="csrf-token"]').attr('content')
, title: info.event.title
, start: start
, end: end
, id: info.event.id
}
, type: "PUT"
, success: function(response) {
console.log(response);
}
});
},
});
calendar.render();
});
</script>
</body>
</html>
Paso 6. Routes
Finalmente declaramos rutas necesarias para el CRUD en el archivo routes.php.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\FullCalendarController;
Route::controller(FullCalendarController::class)->group(function(){
Route::get('fullcalendar', 'index');
Route::get('events', 'events')->name('fullcalendar.events');
Route::post('events/add', 'add')->name('fullcalendar.events.add');
Route::put('events/update', 'update')->name('fullcalendar.events.update');
Route::delete('events/destroy', 'destroy')->name('fullcalendar.events.destroy');
});
Y ya solo nos queda abrir el proyecto desde el navegador: http://laravel-fullcalendar.test/fullcalendar y tenemos:

Videito en TikTok 🙂
Enjoy!!!
En este post veremos como enviar solicitudes GET y POST a un API RestFul desde un dispositivo con android. Nuestra apli[...]
Cuarta parte de esta pequeña serie de tutoriales sobre [Crea tu blog con el patrón MVC y php] En esta cuarta entrega ver[...]
«Las palabras que elegimos dan forma a nuestra realidad. La Fuente Educada (Polite Type) es una fuente de código abierto[...]
En este post dejo el código fuente de un blog en PHP desarrollado siguiendo el patrón de diseño MVC (Modelo, Vista y Con[...]
EL patrón MVC (Model, View, Controller) o Modelo, Vista Controlador, es un tipo de diseño que separa en capas bien defin[...]
¿Quieres iniciarte en la programación? ¿Eres un programador impaciente que odia instalar cualquier software en su comput[...]