FullCalendar jquery ajax CakePHP 4

I will create event calendar use jquery ajax on CakePHP 4, I’m browsing tutorial below
https://onlinewebtutorblog.com/cakephp-4-fullcalendar-ajax-crud-tutorial-example/

first step, I’m connect database in
/config/app_local.php

'username' => 'root',
'password' => '',
'database' => 'mydatabase',

second step, I’m create migration file
$ bin/cake bake migration CreateEvents

it will create file 20220330143909_CreateEvents.php and I added some code

<?php
declare(strict_types=1);
use Migrations\AbstractMigration;
class CreateEvents extends AbstractMigration
{
    public function change()
    {
		$table = $this->table('events');

        $table->addColumn("title", "string", [
            "limit" => 120,
            "null" => false
        ]);

        $table->addColumn("start", "date", [
            "null" => false
        ]);

        $table->addColumn("end", "date", [
            "null" => false
        ]);

        $table->create();
    }
}

then running migration to create table
$ bin/cake migrations migrate

The thirds, I will create model entity Events
$ bin/cake bake model Events --no-validation --no-rules

The fourth, I will create Fullcalendar controller
$ bin/cake bake controller Fullcalendar --no-actions

it will create FullcalendarCalendar.php and I added some code

<?php

declare(strict_types=1);

namespace App\Controller;

class FullcalendarController extends AppController
{
    public function initialize(): void
    {
        parent::initialize();
        $this->loadModel("Events");
    }

    public function myEvents()
    {
        // FullCalendar in frontend
    }

    public function loadData()
    {
        if ($this->request->is("ajax")) {
            // on page load this ajax code block will be run
            $data = $this->Events->find()->where([
                'start >=' => $this->request->getQuery('start'),
                'end <=' => $this->request->getQuery('end')
            ])->toList();

            echo json_encode($data);
        }
        die;
    }

    public function ajax()
    {
        if ($this->request->is("ajax")) {

            switch ($this->request->getData('type')) {

                    // For add event
                case 'add':
                    $event = $this->Events->newEmptyEntity();

                    $event = $this->Events->patchEntity($event, $this->request->getData());

                    if ($this->Events->save($event)) {
                        echo json_encode([
                            "status" => 1,
                            "message" => "Event added successfully"
                        ]);
                    }

                    echo json_encode([
                        "status" => 0,
                        "message" => "Failed to add event"
                    ]);
                    die;
                    break;

                    // For update event        
                case 'update':

                    $event = $this->Events->get($this->request->getData("id"));

                    $event = $this->Events->patchEntity($event, $this->request->getData());

                    if ($this->Events->save($event)) {
                        echo json_encode([
                            "status" => 1,
                            "message" => "Event updated successfully"
                        ]);
                    }

                    echo json_encode([
                        "status" => 0,
                        "message" => "Failed to update event"
                    ]);
                    die;
                    break;

                    // For delete event    
                case 'delete':

                    $event = $this->Events->get($this->request->getData("id"));

                    if ($this->Events->delete($event)) {
                        echo json_encode([
                            "status" => 1,
                            "message" => "Event deleted successfully"
                        ]);
                    }

                    echo json_encode([
                        "status" => 0,
                        "message" => "Failed to delete event"
                    ]);
                    die;
                    break;

                default:
                    break;
            }
        }
    }
}

The fifth, I will create my_events.php template inside /templates/Fullcalendar/ folder

<!DOCTYPE html>
<html>

<head>
    <title>CakePHP 4 Fullcalender Tutorial - Online Web Tutor</title>

	<?php
	  echo $this->Html->css('https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css')."\n";
	  echo $this->Html->css('https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.css')."\n";
	  echo $this->Html->css('https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css')."\n";
	?>
	
    
</head>

<body>

    <div class="container">
        <h3 style="text-align: center">CakePHP 4 Fullcalendar Tutorial - Online Web Tutor</h3>
        <div id="calendar"></div>
    </div>
	
	<?php
	  echo $this->Html->script('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js')."\n";
	  echo $this->Html->script('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js')."\n";
	  echo $this->Html->script('https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.js')."\n";
	  echo $this->Html->script('https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js')."\n";
	?>
    <script>
        $(document).ready(function() {

            var calendar = $('#calendar').fullCalendar({
                editable: true,
                events: "/event",
                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('Event Title:');

                    if (title) {
                        var start = $.fullCalendar.formatDate(start, "Y-MM-DD");
                        var end = $.fullCalendar.formatDate(end, "Y-MM-DD");
                        $.ajax({
                            url: "/eventAjax",
                            data: {
                                title: title,
                                start: start,
                                end: end,
                                type: 'add'
                            },
                            type: "POST",
                            success: function(data) {
                                displayMessage("Event Created Successfully");

                                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: '/eventAjax',
                        data: {
                            title: event.title,
                            start: start,
                            end: end,
                            id: event.id,
                            type: 'update'
                        },
                        type: "POST",
                        success: function(response) {

                            displayMessage("Event Updated Successfully");
                        }
                    });
                },
                
                eventClick: function(event) {
                    var deleteMsg = confirm("Do you really want to delete?");
                    if (deleteMsg) {
                        $.ajax({
                            type: "POST",
                            url: '/eventAjax',
                            data: {
                                id: event.id,
                                type: 'delete'
                            },
                            success: function(response) {

                                calendar.fullCalendar('removeEvents', event.id);
                                displayMessage("Event Deleted Successfully");
                            }
                        });
                    }
                }

            });

        });

        function displayMessage(message) {
            toastr.success(message, 'Event');
        }
    </script>

</body>

</html>

The sixth, I will disabled crsf token, by removing some lines Aplication.php code below

->add(new CsrfProtectionMiddleware([
    'httponly' => true,
]))

The seventh, I will add routes.php inside ‘/config’ folder

$routes->connect(
    '/fullcalendar',
    ['controller' => 'Fullcalendar', 'action' => 'myEvents']
);

$routes->connect(
    '/event',
    ['controller' => 'Fullcalendar', 'action' => 'loadData']
);

$routes->connect(
    '/eventAjax',
    ['controller' => 'Fullcalendar', 'action' => 'ajax']
);

The eighth, I will run testing http://localhost/mycakephp/Fullcalendar
but the error displayed below

Parse error: syntax error, unexpected token "return" in C:\xampp\htdocs\mycakephp\src\Application.php on line 109

The tenth, but if I fixed above with normal currently Application.php there’s still error display

Missing Method in FullcalendarController
The action index is not defined in FullcalendarController
Create FullcalendarController::index() in file: src\Controller\FullcalendarController.php

I hope someone help me, which the part to be fix, thanx

I think URLs are case sensitive? You’ve connected /fullcalendar, but tried to go to /Fullcalendar.

Why not skip all the complexity you’ve added with the myEvents action, and just call that index to take advantage of default routing?

thanx Zuluru, my fullcalendar is working, but I’m still confused in method below

public function myEvents()
 {
     // FullCalendar in frontend
 }

what should I chaged, are above linked to call my_events.php so that couldn’t add, edit and delete event

Sorry, I don’t understand what you mean about “couldn’t add, edit and delete event”. Can you provide more details what you’re expecting here?

I mean, help me to create action add, edit and delete event in my fullcalendar :pray:

You said you did bin/cake bake controller Fullcalendar --no-actions. Why --no-actions? bin/cake bake controller Fullcalendar would have created the add, edit and delete actions for you.