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.

Hi, I have just started to use the Fullcalender. The first problem I face ist a 403 forbidden, when posting data via ajax and the controller action ist not started. Did you had to made additional configurations?

Additional Information:
disabled crsf token, by removing some lines Aplication.php
then I get a 500 Internal Serber Error.
So it looks like a config problem. In other pieces of the application I use ajax get requests without problem. But this si a POST, there is no xhr.setRequestHeader. Is this correct?

Error 500 can mean a million things, including that you simply introduced a typo when you removed some lines. Check your logs for details.

OK I have managed things using this Fullcalendar only for display purposes.
An now I am looking for a way to use a variable in different controller actions which content can change. I tried to use ‘$this->group’ when it is defined as global. It is accepting content in the initialize but not in other functions. Any idea why? Or any other solution? Kind regards

New topics should be posted as new questions, to maximize the chances that someone that knows something about that thing will be able to help you.

Also, this question is way too vague. What does “defined as global” mean? What do you mean by “use in different controller actions”? Post some code to demonstrate what you’re trying to do, with an explanation of what you’re expecting and how that’s different from what you’re seeing.