Features

  • Web application for managing doctor appointments
  • Public interface for patients (see available slots and request an appointment)
  • Doctor's management interface (edit and delete appointments)
  • Manager's managements interface (schedule shifts and create appointment slots)
  • Uses DayPilot Pro for JavaScript (trial version)
  • Sample SQLite and MySQL database

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.

User Interface

The user interface includes three independent views:

1. Patients

html5-doctor-appointment-scheduling-javascript-php-overview-patient.png

Patients can access a public calendar (weekly view) that displays available slots. They can request an appointment at the specified time (one of the free slots).

2. Doctors

html5-doctor-appointment-scheduling-javascript-php-overview-doctor.png

Doctors can see all slots (free slots and appointments) with details about the patient.

3. Managers

html5-doctor-appointment-scheduling-javascript-php-overview-manager.png

Managers can see an integrated view of all doctors and their appointments. They manage shifts and define the time slots.

1. Appointment UI for Patients (index.php)

html5-doctor-appointment-scheduling-javascript-php-patient.png

The patient interface is created using DayPilot JavaScript Calendar control:

HTML5

<!-- Calendar placeholder -->
<div id="calendar"></div>

JavaScript

<script>

  var calendar = new DayPilot.Calendar("calendar");
  calendar.viewType = "Week";
  calendar.init();

</script>

The calendar is switched to the week view using viewType property.

It loads the available slots from the server side using a simple AJAX request that returns the slots as a JSON message:

  function loadEvents() {
      var params = {
          start: nav.visibleStart().toString(),
          end: nav.visibleEnd().toString()
      };

      $.post("backend_events_free.php", JSON.stringify(params), function(data) {
          calendar.events.list = data;
          calendar.update();
      });
  }

The backend_events.free.php script return slots that were created in advance by the shift administrator. Only the free slots are loaded (status == "free").

The time slots were created in advance when planning the shifts using the manager's interface (manager.php; see below).

<?php
require_once '_db.php';

$json = file_get_contents('php://input');
$params = json_decode($json);

$session_id = session_id();

$stmt = $db->prepare("SELECT * FROM appointment JOIN doctor ON appointment.doctor_id = doctor.doctor_id WHERE (appointment_status = 'free' OR (appointment_status <> 'free' AND appointment_patient_session = :session)) AND NOT ((appointment_end <= :start) OR (appointment_start >= :end))");
$stmt->bindParam(':start', $params->start);
$stmt->bindParam(':end', $params->end);
$stmt->bindParam(":session", $session_id);
$stmt->execute();
$result = $stmt->fetchAll();

class Event {}
class Tags {}
$events = array();

foreach($result as $row) {
  $e = new Event();
  $e->id = $row['appointment_id'];
  $e->text = "";
  $e->start = $row['appointment_start'];
  $e->end = $row['appointment_end'];
  $e->tags = new Tags();
  $e->tags->status = $row['appointment_status'];
  $e->tags->doctor = $row['doctor_name'];
  $events[] = $e;
}

header('Content-Type: application/json');
echo json_encode($events);

?>

Sample JSON response:

[
  {"id":"30","text":"","start":"2016-04-21T09:00:00","end":"2016-04-21T10:00:00","tags":{"status":"free","doctor":"Doctor 3"}},
  {"id":"31","text":"","start":"2016-04-21T10:00:00","end":"2016-04-21T11:00:00","tags":{"status":"free","doctor":"Doctor 3"}},
  {"id":"33","text":"","start":"2016-04-21T12:00:00","end":"2016-04-21T13:00:00","tags":{"status":"free","doctor":"Doctor 3"}},
  {"id":"34","text":"","start":"2016-04-21T14:00:00","end":"2016-04-21T15:00:00","tags":{"status":"free","doctor":"Doctor 3"}},
  {"id":"35","text":"","start":"2016-04-21T15:00:00","end":"2016-04-21T16:00:00","tags":{"status":"free","doctor":"Doctor 3"}},
  {"id":"36","text":"","start":"2016-04-21T16:00:00","end":"2016-04-21T17:00:00","tags":{"status":"free","doctor":"Doctor 3"}},
  {"id":"37","text":"","start":"2016-04-21T17:00:00","end":"2016-04-21T18:00:00","tags":{"status":"free","doctor":"Doctor 3"}}
]

The Calendar is read-only. Drag and drop actions (such as moving, resizing) are forbidden:

<script>

  var calendar = new DayPilot.Calendar("calendar");
  calendar.viewType = "Week";
  calendar.timeRangeSelectedHandling = "Disabled";
  calendar.eventMoveHandling = "Disabled";
  calendar.eventResizeHandling = "Disabled";
  // ...
  calendar.init();

</script>

The only action that is allowed is clicking an existing time slot:

<script>

  var calendar = new DayPilot.Calendar("calendar");

  // ...

  calendar.onEventClick = function(args) {
      if (args.e.tag("status") !== "free") {
          calendar.message("You can only request a new appointment in a free slot.");
          return;
      }

      var modal = new DayPilot.Modal({
          onClosed: function(args) {
              if (args.result) {  // args.result is empty when modal is closed without submitting
                  loadEvents();
              }
          }
      });

      modal.showUrl("appointment_request.php?id=" + args.e.id());
  };

  calendar.init();

</script>

It opens a modal dialog ("appointment_request.php") where the patient can request an appointment.

html5-doctor-appointment-scheduling-javascript-php-request.png

As soon as the appointment request is saved the slot status is changed to "waiting" and the color is changed to orange. 

In this demo, the user identification is saved using the session ID. In a standard application, you would use the user id instead. 

index.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>HTML5 Doctor Appointment Scheduling (JavaScript/PHP)</title>

        <link type="text/css" rel="stylesheet" href="css/layout.css" />

        <!-- DayPilot library -->
        <script src="js/daypilot/daypilot-all.min.js"></script>
    </head>
    <body>
        <?php require_once '_header.php'; ?>

        <div class="main">
            <?php require_once '_navigation.php'; ?>

            <div>

                <div style="float:left; width:160px">
                    <div id="nav"></div>
                </div>
                <div style="margin-left: 160px">
                    <div class="space">Available time slots:</div>
                    <div id="calendar"></div>
                </div>

            </div>
        </div>

        <script src="js/jquery-1.9.1.min.js"></script>
        <script src="js/daypilot/daypilot-all.min.js"></script>

        <script>
            var nav = new DayPilot.Navigator("nav");
            nav.selectMode = "week";
            nav.showMonths = 3;
            nav.skipMonths = 3;
            nav.onTimeRangeSelected = function(args) {
                 loadEvents(args.start.firstDayOfWeek(), args.start.addDays(7));
            };
            nav.init();

            var calendar = new DayPilot.Calendar("calendar");
            calendar.viewType = "Week";
            calendar.timeRangeSelectedHandling = "Disabled";
            calendar.eventMoveHandling = "Disabled";
            calendar.eventResizeHandling = "Disabled";
            calendar.onBeforeEventRender = function(args) {
                if (!args.data.tags) {
                    return;
                }
                switch (args.data.tags.status) {
                    case "free":
                        args.data.barColor = "green";
                        args.data.html = "Available<br/>" + args.data.tags.doctor;
                        args.data.toolTip = "Click to request this time slot";
                        break;
                    case "waiting":
                        args.data.barColor = "orange";
                        args.data.html = "Your appointment, waiting for confirmation";
                        break;
                    case "confirmed":
                        args.data.barColor = "#f41616";  // red
                        args.data.html = "Your appointment, confirmed";
                        break;
                }
            };
            calendar.onEventClick = function(args) {
                if (args.e.tag("status") !== "free") {
                    calendar.message("You can only request a new appointment in a free slot.");
                    return;
                }

                var modal = new DayPilot.Modal({
                    onClosed: function(args) {
                        if (args.result) {  // args.result is empty when modal is closed without submitting
                            loadEvents();
                        }
                    }
                });

                modal.showUrl("appointment_request.php?id=" + args.e.id());
            };
            calendar.init();

            loadEvents();

            function loadEvents(day) {
                var start = nav.visibleStart() > new DayPilot.Date() ? nav.visibleStart() : new DayPilot.Date();

                var params = {
                    start: start.toString(),
                    end: nav.visibleEnd().toString()
                };

                $.post("backend_events_free.php", JSON.stringify(params), function(data) {
                    if (day) {
                        calendar.startDate = day;
                    }
                    calendar.events.list = data;
                    calendar.update();

                    nav.events.list = data;
                    nav.update();

                });
            }
        </script>

    </body>
</html>

2. Appointment Administration UI for Doctors (doctor.php)

html5-doctor-appointment-scheduling-javascript-php-admin.png

The doctors can use a special user interface to manage their appointments. They can see all slots (including free ones).

The layout is similar to what the patients can see but the configuration is different.

Appointment slot drag and drop operations are allowed:

calendar.onEventMoved = function(args) {
    $.post("backend_move.php", JSON.stringify(args), function(data) {
        calendar.message(data.message);
    });
};
calendar.onEventResized = function(args) {
    $.post("backend_move.php", JSON.stringify(args), function(data) {
        calendar.message(data.message);
    });
};

The slots use a color code depending on the status. The color of the appointment bar is customized using BeforeEventRender event:

calendar.onBeforeEventRender = function(args) {
    if (!args.data.tags) {
        return;
    }
    switch (args.data.tags.status) {
        case "free":
            args.data.barColor = "green";
            break;
        case "waiting":
            args.data.barColor = "orange";
            break;
        case "confirmed":
            args.data.barColor = "#f41616";  // red
            break;
    }
};

The slots/events are loaded from a different JSON endpoint ("backend_events_doctor.php") - it returns all slots for the selected doctor (including slots from the past and existing reservations):

function loadEvents(day) {
    var params = {
        doctor: $("#doctor").val(),
        start: nav.visibleStart().toString(),
        end: nav.visibleEnd().toString()
    };

    $.post("backend_events_doctor.php", JSON.stringify(params), function(data) {
        calendar.events.list = data;
        calendar.update();
    });
} 

Click on an appointment slot opens an special edit page using a modal dialog:

calendar.onEventClick = function(args) {
    var modal = new DayPilot.Modal({
        onClosed: function(args) {
            if (args.result) {  // args.result is empty when modal is closed without submitting
                loadEvents();
            }
        }
    });

    modal.showUrl("appointment_edit.php?id=" + args.e.id());
};

html5-doctor-appointment-scheduling-javascript-php-edit.png

This edit page ("appointment_edit.php") allows changing the status and the patient name. It's possible to delete the appointment slot using "Delete" button.

doctor.php

<?php
    require_once '_db.php';
?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>HTML5 Doctor Appointment Scheduling (JavaScript/PHP)</title>

        <link type="text/css" rel="stylesheet" href="css/layout.css" />

        <!-- DayPilot library -->
        <script src="js/daypilot/daypilot-all.min.js"></script>
    </head>
    <body>
        <?php require_once '_header.php'; ?>

        <div class="main">
            <?php require_once '_navigation.php'; ?>

            <div>

                <div style="float:left; width:160px">
                    <div id="nav"></div>
                </div>
                <div style="margin-left: 160px">
                    <div class="space">
                        <select id="doctor" name="doctor">
                        <?php
                            foreach($db->query('SELECT * FROM [doctor] ORDER BY [doctor_name]') as $item) {
                                echo "<option value='".$item["doctor_id"]."'>".$item["doctor_name"]."</option>";
                            }
                        ?>
                        </select>
                    </div>
                    <div id="calendar"></div>
                </div>

            </div>
        </div>

        <script src="js/jquery-1.9.1.min.js"></script>
        <script src="js/daypilot/daypilot-all.min.js"></script>

        <script>
            var nav = new DayPilot.Navigator("nav");
            nav.selectMode = "week";
            nav.showMonths = 3;
            nav.skipMonths = 3;
            nav.onTimeRangeSelected = function(args) {
                 loadEvents(args.start.firstDayOfWeek(), args.start.addDays(7));
            };
            nav.init();

            var calendar = new DayPilot.Calendar("calendar");
            calendar.viewType = "Week";
            calendar.timeRangeSelectedHandling = "Disabled";

            calendar.onEventMoved = function(args) {
                $.post("backend_move.php", JSON.stringify(args), function(data) {
                    calendar.message(data.message);
                });
            };
            calendar.onEventResized = function(args) {
                $.post("backend_move.php", JSON.stringify(args), function(data) {
                    calendar.message(data.message);
                });
            };
            calendar.onBeforeEventRender = function(args) {
                if (!args.data.tags) {
                    return;
                }
                switch (args.data.tags.status) {
                    case "free":
                        args.data.barColor = "green";
                        break;
                    case "waiting":
                        args.data.barColor = "orange";
                        break;
                    case "confirmed":
                        args.data.barColor = "#f41616";  // red
                        break;
                }
            };

            calendar.onEventClick = function(args) {
                var modal = new DayPilot.Modal({
                    onClosed: function(args) {
                        if (args.result) {  // args.result is empty when modal is closed without submitting
                            loadEvents();
                        }
                    }
                });

                modal.showUrl("appointment_edit.php?id=" + args.e.id());
            };
            calendar.init();

            loadEvents();

            function loadEvents(day) {
                var start = nav.visibleStart() > new DayPilot.Date() ? nav.visibleStart() : new DayPilot.Date();

                var params = {
                    doctor: $("#doctor").val(),
                    start: start.toString(),
                    end: nav.visibleEnd().toString()
                };

                $.post("backend_events_doctor.php", JSON.stringify(params), function(data) {
                    if (day) {
                        calendar.startDate = day;
                    }
                    calendar.events.list = data;
                    calendar.update();

                    nav.events.list = data;
                    nav.update();
                });
            }

            $(document).ready(function() {
                $("#doctor").change(function() {
                    loadEvents();
                });
            });
        </script>

    </body>
</html>

3. Shift Administration UI for Managers (manager.php)

html5-doctor-appointment-scheduling-javascript-php-manager.png

The manager's view uses DayPilot JavaScript Scheduler to display appointments of all doctors side by side.

HTML5

<!-- Scheduler placeholder -->
<div id="scheduler"></div>

JavaScript

<script>
  var scheduler = new DayPilot.Scheduler("scheduler");
  scheduler.scale = "Manual";
  scheduler.timeline = getTimeline();
  scheduler.timeHeaders = getTimeHeaders();
  scheduler.resources = [
    {"id":"1","name":"Doctor 1"},
    {"id":"2","name":"Doctor 2"},
    {"id":"3","name":"Doctor 3"},
    {"id":"4","name":"Doctor 4"},
    {"id":"5","name":"Doctor 5"}
  ];
  scheduler.init();
</script>

New appointment slots can be creating using drag and drop. As soon as you select a date range it will be filled with slots with a predefined size (1 hour by default)

html5-doctor-appointment-scheduling-javascript-php-selecting.png

<script>
  var scheduler = new DayPilot.Scheduler("scheduler");
  
  // ...
  
  scheduler.onTimeRangeSelected = function(args) {
      var dp = scheduler;
      var scale = $("input[name=scale]:checked").val();

      var params = {
          start: args.start.toString(),
          end: args.end.toString(),
          resource: args.resource,
          scale: scale
      };

      $.post("backend_create.php", JSON.stringify(params), function(data) {
          loadEvents();
          dp.message(data.message);
      });

      dp.clearSelection();

  };
  scheduler.init();
</script>

The appointment slots can be deleted using a built-in "delete" icon:

html5-doctor-appointment-scheduling-javascript-php-delete.png

<script>
  var scheduler = new DayPilot.Scheduler("scheduler");
  
  // ...
  
  scheduler.onEventDeleted = function(args) {
      var params = {
          id: args.e.id(),
      };
      $.post("backend_delete.php", JSON.stringify(params), function(data) {
          scheduler.message("Deleted.");
      });
  };

  scheduler.init();
</script>

The appointment status is highlighted using a custom duration bar color (green/orange/red):

<script>
  var scheduler = new DayPilot.Scheduler("scheduler");
  
  // ...
  
  scheduler.onBeforeEventRender = function(args) {
      switch (args.data.tags.status) {
          case "free":
              args.data.barColor = "green";
              args.data.deleteDisabled = $('input[name=scale]:checked').val() === "shifts";  // only allow deleting in the more detailed hour scale mode
              break;
          case "waiting":
              args.data.barColor = "orange";
              args.data.deleteDisabled = true;
              break;
          case "confirmed":
              args.data.barColor = "#f41616";  // red
              args.data.deleteDisabled = true;
              break;
      }
  };

  scheduler.init();
</script>

manager.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>HTML5 Doctor Appointment Scheduling (JavaScript/PHP)</title>

        <link type="text/css" rel="stylesheet" href="css/layout.css" />

        <!-- DayPilot library -->
        <script src="js/daypilot/daypilot-all.min.js"></script>
    </head>
    <body>
        <?php require_once '_header.php'; ?>

        <div class="main">
            <?php require_once '_navigation.php'; ?>

            <div>

                <div style="float:left; width:160px">
                    <div id="nav"></div>
                </div>
                <div style="margin-left: 160px">
                    <div class="space">
                    Slots: <button id="clear">Clear</button> Deletes all free slots this month
                    </div>
                    <div class="space options">
                        Scale:
                        <label for='scale-hours'><input type="radio" value="hours" name="scale" id='scale-hours' checked> Hours</label>
                        <label for='scale-shifts'><input type="radio" value="shifts" name="scale" id='scale-shifts'> Shifts</label>
                        <label for="business-only"><input type="checkbox" id="business-only"> Hide non-business hours</label>
                    </div>
                    <div id="scheduler"></div>
                </div>

            </div>
        </div>

        <script src="js/jquery-1.9.1.min.js"></script>
        <script src="js/daypilot/daypilot-all.min.js"></script>

        <script>
            var nav = new DayPilot.Navigator("nav");
            nav.selectMode = "month";
            nav.showMonths = 3;
            nav.skipMonths = 3;
            nav.onTimeRangeSelected = function(args) {
                 //loadEvents(args.start.firstDayOfWeek(), args.start.addDays(7));
                if (scheduler.visibleStart().getDatePart() <= args.day && args.day < scheduler.visibleEnd()) {
                    scheduler.scrollTo(args.day, "fast");  // just scroll
                }
                else {
                    loadEvents(args.day);  // reload and scroll
                }
            };
            nav.init();

            var scheduler = new DayPilot.Scheduler("scheduler");
            scheduler.visible = false; // will be displayed after loading the resources
            scheduler.scale = "Manual";
            scheduler.timeline = getTimeline();
            scheduler.timeHeaders = getTimeHeaders();
            scheduler.useEventBoxes = "Never";
            scheduler.eventDeleteHandling = "Update";
            scheduler.eventClickHandling = "Disabled";
            scheduler.eventMoveHandling = "Disabled";
            scheduler.eventResizeHandling = "Disabled";
            scheduler.allowEventOverlap = false,
            scheduler.onBeforeTimeHeaderRender = function(args) {
                args.header.html = args.header.html.replace(" AM", "a").replace(" PM", "p");  // shorten the hour header
            };
            scheduler.onBeforeEventRender = function(args) {
                switch (args.data.tags.status) {
                    case "free":
                        args.data.barColor = "green";
                        args.data.deleteDisabled = $('input[name=scale]:checked').val() === "shifts";  // only allow deleting in the more detailed hour scale mode
                        break;
                    case "waiting":
                        args.data.barColor = "orange";
                        args.data.deleteDisabled = true;
                        break;
                    case "confirmed":
                        args.data.barColor = "#f41616";  // red
                        args.data.deleteDisabled = true;
                        break;
                }
            };
            scheduler.onEventDeleted = function(args) {
                var params = {
                    id: args.e.id(),
                };
                $.post("backend_delete.php", JSON.stringify(params), function(data) {
                    scheduler.message("Deleted.");
                });

            };
            scheduler.onTimeRangeSelected = function(args) {
                var dp = scheduler;
                var scale = $("input[name=scale]:checked").val();

                var params = {
                    start: args.start.toString(),
                    end: args.end.toString(),
                    resource: args.resource,
                    scale: scale
                };

                $.post("backend_create.php", JSON.stringify(params), function(data) {
                    loadEvents();
                    dp.message(data.message);
                });

                dp.clearSelection();

            };
            scheduler.init();


            loadResources();
            loadEvents(DayPilot.Date.today());

            function loadEvents(day) {
                var from = scheduler.visibleStart();
                var to = scheduler.visibleEnd();
                if (day) {
                    from = new DayPilot.Date(day).firstDayOfMonth();
                    to = from.addMonths(1);
                }

                var params = {
                    start: from.toString(),
                    end: to.toString()
                };

                $.post("backend_events.php", JSON.stringify(params), function(data) {
                    scheduler.timeline = getTimeline(day);
                    scheduler.events.list = data;
                    scheduler.update();
                    scheduler.scrollTo(day, "fast", "left");

                    nav.events.list = data;
                    nav.update();
                });
            }

            function loadResources() {
                $.post("backend_resources.php", function(data) {
                    scheduler.resources = data;
                    scheduler.visible = true;
                    scheduler.update();
                });
            }

            function getTimeline(date) {
                var date = date || DayPilot.Date.today();
                var start = new DayPilot.Date(date).firstDayOfMonth();
                var days = start.daysInMonth();
                var scale = $("input[name=scale]:checked").val();
                var businessOnly = $("#business-only").prop("checked");

                var morningShiftStarts = 9;
                var morningShiftEnds = 13;
                var afternoonShiftStarts = 14;
                var afternoonShiftEnds = 18;

                if (!businessOnly) {
                    var morningShiftStarts = 0;
                    var morningShiftEnds = 12;
                    var afternoonShiftStarts = 12;
                    var afternoonShiftEnds = 24;
                }

                var timeline = [];

                var increaseMorning;  // in hours
                var increaseAfternoon;  // in hours
                switch (scale) {
                    case "hours":
                        increaseMorning = 1;
                        increaseAfternoon = 1;
                        break;
                    case "shifts":
                        increaseMorning = morningShiftEnds - morningShiftStarts;
                        increaseAfternoon = afternoonShiftEnds - afternoonShiftStarts;
                        break;
                    default:
                        throw "Invalid scale value";
                }

                for (var i = 0; i < days; i++) {
                    var day = start.addDays(i);

                    for (var x = morningShiftStarts; x < morningShiftEnds; x += increaseMorning)
                    {
                        timeline.push({start: day.addHours(x), end: day.addHours(x + increaseMorning) });
                    }
                    for (var x = afternoonShiftStarts; x < afternoonShiftEnds; x += increaseAfternoon)
                    {
                        timeline.push({start: day.addHours(x), end: day.addHours(x + increaseAfternoon) });
                    }
                }

                return timeline;
            }

            function getTimeHeaders() {
                var scale = $('input[name=scale]:checked').val();
                switch (scale) {
                    case "hours":
                        return [ { groupBy: "Month" }, { groupBy: "Day", format: "dddd d" }, { groupBy: "Hour", format: "h tt"}];
                        break;
                    case "shifts":
                        return [ { groupBy: "Month" }, { groupBy: "Day", format: "dddd d" }, { groupBy: "Cell", format: "tt"}];
                        break;
                }
            }

            $(document).ready(function() {
                $("#business-only").click(function() {
                    scheduler.timeline = getTimeline();
                    scheduler.update();
                });
                $("input[name=scale]").click(function() {
                    scheduler.timeline = getTimeline();
                    scheduler.timeHeaders = getTimeHeaders();
                    scheduler.update();
                });
                $("#clear").click(function() {
                    var dp = scheduler;
                    var params = {
                        start: dp.visibleStart(),
                        end: dp.visibleEnd()
                    };
                    $.post("backend_clear.php", JSON.stringify(params), function(data) {
                        dp.message(data.message);
                        loadEvents();
                    });
                });
            });

        </script>

    </body>
</html>

Database (MySQL/SQLite)

The tutorial uses a simple database with just two tables ('appointment', 'doctor').

By default, it uses SQLite storage:

  • The database is stored in daypilot.sqlite file in the application root directory.
  • Make sure the application has permissions to write to the database file.
  • You can use SQLiteStudio or a similar to view and edit the database.

SQLite SQL Schema

CREATE TABLE appointment (
    appointment_id              INTEGER       PRIMARY KEY AUTOINCREMENT
                                              NOT NULL,
    appointment_start           DATETIME      NOT NULL,
    appointment_end             DATETIME      NOT NULL,
    appointment_patient_name    VARCHAR (100),
    appointment_status          VARCHAR (100) DEFAULT ('free') 
                                              NOT NULL,
    appointment_patient_session VARCHAR (100),
    doctor_id                   INTEGER       NOT NULL
);

CREATE TABLE doctor (
    doctor_id   INTEGER       PRIMARY KEY AUTOINCREMENT
                              NOT NULL,
    doctor_name VARCHAR (100) NOT NULL
);

Using MySQL

In the application root, there are three database-related files:

  • _db.php - the configuration currently in use
  • _db_sqlite.php - SQLite configuration
  • _db_mysql.php - MySQL configuration

If you want to switch from SQLite (default configuraiton) to MySQL you need to do the following:

  • copy _db_mysql.php file to _db.php
  • edit _db.php and adjust your database connection settings:
<?php
$host = "127.0.0.1";
$port = 3306;
$username = "username";   // change the user name
$password = "password";   // change the password
$database = "doctor";

The script will create the database ('doctor' by default) automatically if it doesn't exist, create the required tables and add some sample data to the 'doctor' table.