mirror of
https://github.com/alextselegidis/easyappointments.git
synced 2024-12-22 14:42:23 +03:00
* Added content to implementation.tex
* Updated the diagram files.
This commit is contained in:
parent
8f70217b33
commit
fb196ed719
15 changed files with 411 additions and 49 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
doc/thesis/diagrams/ea-ad-provider-available-hours.io
Normal file
1
doc/thesis/diagrams/ea-ad-provider-available-hours.io
Normal file
|
@ -0,0 +1 @@
|
|||
<mxGraphModel dx="800" dy="800" grid="1" guides="1" tooltips="1" connect="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" style="default-style2"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="" style="ellipse;shape=startState;fillColor=#000000;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="122.5" y="20" width="30" height="30" as="geometry"/></mxCell><mxCell id="3" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" source="2" parent="1" target="4"><mxGeometry x="122.5" y="20" as="geometry"><mxPoint x="137.5" y="90" as="targetPoint"/></mxGeometry></mxCell><mxCell id="4" value="Λήψη Πλάνου Εργασίας
& Καταχωρημένων Ραντεβού" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="76" width="165" height="40" as="geometry"/></mxCell><mxCell id="5" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="6"><mxGeometry x="77" y="76" as="geometry"><mxPoint x="137" y="156" as="targetPoint"/><mxPoint x="137" y="116" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="6" value="Διάσταση Πλάνου Εργασίας
Από Διαλείμματα" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="145" width="165" height="40" as="geometry"/></mxCell><mxCell id="7" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="10"><mxGeometry x="77" y="145" as="geometry"><mxPoint x="137" y="225" as="targetPoint"/><mxPoint x="137" y="185" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="10" value="Διάσταση Πλάνου Εργασίας
Από Καταχωρημένα Ραντεβού" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="214" width="165" height="40" as="geometry"/></mxCell><mxCell id="11" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="12"><mxGeometry x="77" y="214" as="geometry"><mxPoint x="137" y="294" as="targetPoint"/><mxPoint x="137" y="254" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="12" value="Υπολογισμός Διαθέσιμων
Ωρών Ραντεβού" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="284" width="165" height="40" as="geometry"/></mxCell><mxCell id="13" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="14"><mxGeometry x="77" y="284" as="geometry"><mxPoint x="137" y="364" as="targetPoint"/><mxPoint x="137" y="324" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="14" value="" style="ellipse;shape=endState;fillColor=#000000;strokeColor=#ff0000" vertex="1" parent="1"><mxGeometry x="122.5" y="352" width="30" height="30" as="geometry"/></mxCell></root></mxGraphModel>
|
1
doc/thesis/diagrams/ea-ad-sync-appointments.io
Normal file
1
doc/thesis/diagrams/ea-ad-sync-appointments.io
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 49 KiB |
Binary file not shown.
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
BIN
doc/thesis/images/ad-provider-available-hours.png
Normal file
BIN
doc/thesis/images/ad-provider-available-hours.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
doc/thesis/images/ad-sync-appointments.png
Normal file
BIN
doc/thesis/images/ad-sync-appointments.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -45,7 +45,7 @@
|
|||
commentstyle = \color{gray},
|
||||
emph =[1]{php},
|
||||
emphstyle =[1]\color{black},
|
||||
emph =[2]{if,and,or,else,public,function,try,catch},
|
||||
emph =[2]{if,and,or,else,public,function,try,catch,return},
|
||||
emphstyle =[2]\color{dkyellow},
|
||||
numbers = left,
|
||||
tabsize = 2,
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
Σε αυτό το κεφάλαιο γίνεται ανάλυση του συστήματος στα επιμέρους μέρη και περιγράφεται η διαδικασία της υλοποίησης τους. Επεξηγούνται επίσης τα σημαντικότερα σημεία στον κώδικα και οι αλγόριθμοι που χρησιμοποιούνται για την επίλυση των κυριότερων λειτουργιών. Έχουν συμπεριληφθεί τμήματα κώδικα αλλά και διαγράμματα τα οποία βοηθούν στην κατανόηση των λύσεων που έχουν χρησιμοποιηθεί.
|
||||
|
||||
%% ==================================================
|
||||
%% ΔΕΔΟΜΕΝΑ ΣΥΣΤΗΜΑΤΟΣ
|
||||
%% ΑΝΑΛΥΣΗ ΔΕΔΟΜΕΝΩΝ
|
||||
%% ==================================================
|
||||
\section{Δεδομένα Συστήματος}
|
||||
Το κυριότερο πρόβλημα που προσπαθεί να λύσει το σύστημα είναι η κράτηση και η διαχείριση ραντεβού από μια επιχείριση. Σε αυτήν την περίπτωση χρήσης έχει επικεντρωθεί η σχεδίαση και η υλοποίηση του συστήματος το οποίο περιέχει και άλλες δυνατότητες οι οποίες μπορούν όμως να θεωρηθούν λιγότερο σημαντικές. Έχοντας υπόψιν την έννοια "ραντεβού" ως την κύρια οντότητα της εφαρμογής, σχεδιάστηκε το παρακάτω μοντέλο το οποίο διευκρινίζει τις σχέσεις των υπόλοιπων οντοτήτων σε σχέση με το ραντεβού αλλά και μεταξύ τους.
|
||||
\section{Ανάλυση Δεδομένων}
|
||||
Το κυριότερο πρόβλημα που προσπαθεί να λύσει το σύστημα είναι η κράτηση και η διαχείριση ραντεβού από μια επιχείριση. Σε αυτήν την περίπτωση χρήσης έχει επικεντρωθεί η σχεδίαση και η υλοποίηση του συστήματος το οποίο περιέχει και άλλες δυνατότητες οι οποίες μπορούν όμως να θεωρηθούν λιγότερο σημαντικές. Έχοντας υπόψιν την έννοια "ραντεβού" ως την κύρια οντότητα της εφαρμογής, σχεδιάστηκε το παρακάτω μοντέλο το οποίο διευκρινίζει τις σχέσεις των οντοτήτων του συστήματος μεταξύ τους.
|
||||
|
||||
\begin{figure}[ht!]
|
||||
\centering
|
||||
|
@ -25,33 +25,12 @@
|
|||
|
||||
Για την διαχείριση των δεδομένων της βάσης δημιουργήθηκαν ειδικές κλάσεις (models) οι οποίες περιέχουν μεθόδους που χρησιμοποιούνται από τους controllers του συστήματος. Το CodeIgniter δίνει στον προγραμματιστή ένα δικό του μέσο επικοινωνίας με την βάση δεδομένων, το οποίο είναι ένα πολύ ισχυρό και ευέλικτο εργαλείο. Η επονομαζόμενη Database Class του CodeIgniter επιτρέπει στον προγραμματιστεί να εκτελεί ερωτήματα προς την βάση, να παράγει αποτελέσματα και να τα αναλύει σε ξεχωριστές εγγραφές, να κρατάει στην μνήμη ερωτήματα για γρηγορότερη ανταπόκριση (query caching) και κυριότερο την κλάση Active Record. Η κλάση αυτή έχει έναν δικό της τρόπο για την εκτέλεση των ερωτημάτων προς την βάση. Όλα τα τμήματα ενός τυπικού ερωτήματος είναι μέθοδοι σε αυτήν την κλάση και έτσι ο προγραμματιστείς χρησιμοποιεί τις μεθόδους αυτές για να επικοινωνήσει με την βάση δεδομένων. Το θετικό είναι ότι ανεξαρτήτως τον τύπο της βάσης η κλάση αυτή λειτουργεί με τον ίδιο τρόπο (MySQL, PostGre, MSSQL κτλ). Η τεχνική αυτή λέγεται Active Record Database Pattern και έχει αν κάνει με την αλλαγή adapter στην κλάση ανάλογα με τον τύπο της βάσης. Σε κάθε περίπτωση όμως ο τρόπος λειτουργίας της είναι ο ίδιος. Στο παρακάτω τμήμα κώδικα αναφέρεται ένα παράδειγμα για το πως μπορεί να βρεθεί το αναγνωριστικό μιας εγγραφής χρησιμοποιώντας ως κλειδί την διεύθυνση email.
|
||||
|
||||
\begin{verbatim}
|
||||
public function find_record_id($admin) {
|
||||
if (!isset($admin['email'])) {
|
||||
throw new Exception('Admin email was not provided: '
|
||||
. print_r($admin, TRUE));
|
||||
}
|
||||
|
||||
$result = $this->db
|
||||
->select('ea_users.id')
|
||||
->from('ea_users')
|
||||
->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'inner')
|
||||
->where('ea_users.email', $admin['email'])
|
||||
->where('ea_roles.slug', DB_SLUG_ADMIN)
|
||||
->get();
|
||||
|
||||
if ($result->num_rows() == 0) {
|
||||
throw new Exception('Could not find admin record id.');
|
||||
}
|
||||
|
||||
return intval($result->row()->id);
|
||||
}
|
||||
\end{verbatim}
|
||||
\lstinputlisting{snippets/find_record_id.php}
|
||||
|
||||
%% ==================================================
|
||||
%% ΑΡΧΙΤΕΚΤΟΝΙΚΗ ΤΟΥ ΚΩΔΙΚΑ
|
||||
%% ΑΡΧΙΤΕΚΤΟΝΙΚΗ ΚΩΔΙΚΑ
|
||||
%% ==================================================
|
||||
\section{Αρχιτεκτονική Του Κώδικα}
|
||||
\section{Αρχιτεκτονική Κώδικα}
|
||||
Η εφαρμογή είναι γραμμένη χρησιμοποιώντας τις εξής τεχνολογίες: PHP, Javascript, HTML, CSS, MySQL. Εκτός αυτών έχουν χρησιμοποιηθεί και κάποια βοηθητικά εργαλεία τα οποία διευκολύνουν τον προγραμματιστή στο να πετύχει καλύτερο αποτέλεσμα σε μικρότερο χρόνο. Αυτά τα εργαλεία (frameworks) όπως έχουν αναφερθεί και σε προηγούμενο κεφάλαιο είναι τα CodeIgniter (PHP), jQuery (Javascript), Bootstrap (CSS + Javascript).
|
||||
|
||||
Όσον αφορά την αρχιτεκτονική του κώδικα έχει επιλεχθεί το μοντέλο MVC (Model - View - Controller) και αυτό υλοποιείται με την χρήση του CodeIgniter με άριστη απόδοση. Ο κώδικας PHP έχει χωριστεί σε τρία μέρη και έτσι χρησιμοποιείται σε όλη την εφαρμογή. Με αυτόν τον τρόπο βελτιώνονται οι συνθήκες συντήρησης γιατί είναι ξεκάθαρο σε ποιο από τα τρία ξεχωριστά σημεία ανήκει ένα τμήμα κώδικα. Έχουν συγγραφεί και δοκιμαστεί κλάσεις models για κάθε οντότητα οι οποίες αναλαμβάνουν την διαχείριση των δεδομένων με την βάση. Επίσης έχουν δημιουργηθεί views για κάθε σελίδα που πιθανόν θα δει ο χρήστης τα οποία συνδέονται με ένα κομμάτι CSS κώδικα, υπεύθυνο για την μορφοποίηση της σελίδας. Τέλος τον συντονισμό των προηγούμενων αναλαμβάνουν οι κλάσεις controllers οι οποίες είτε είναι υπεύθυνες για την σωστή φόρτωση μιας σελίδας της εφαρμογής είτε απαντούν σε κλήσεις της JavaScript που γίνονται μέσω της τεχνολογίας AJAX.
|
||||
|
@ -70,9 +49,9 @@ public function find_record_id($admin) {
|
|||
\end{figure}
|
||||
|
||||
%% ==================================================
|
||||
%% ΥΛΟΠΟΙΗΣΗ ΤΟΥ ΣΥΣΤΗΜΑΤΟΣ
|
||||
%% ΥΛΟΠΟΙΗΣΗ ΣΥΣΤΗΜΑΤΟΣ
|
||||
%% ==================================================
|
||||
\section{Υλοποίηση Του Συστήματος}
|
||||
\section{Υλοποίηση Συστήματος}
|
||||
Εφόσον ο αρχικός σχεδιασμός είχε ολοκληρωθεί ξεκίνησε η υλοποίηση της εφαρμογής με πρώτη εργασία τον σχεδιασμό της βάσης δεδομένων. Έχοντας ήδη σχεδιασμένο το domain model η δημιουργία του σχήματος της βάσης έγινε γρήγορα και διατηρήθηκε ως την ολοκλήρωση του έργου με μικρές προσθήκες όπου ήταν απαραίτητο.
|
||||
|
||||
Στην συνέχεια, πριν γραφεί κώδικας θα έπρεπε να γίνει η επιλογή και το στήσιμο των εξωτερικών βιβλιοθηκών που θα κρίνονταν απαραίτητα για την λειτουργία του συστήματος. Σε αυτήν την φάση επιλέχθηκαν οι βασικές βιβλιοθήκες (CodeIgniter, Google API Library, jQuery, Bootstrap) και επιλέχθηκε η σημαντικότερη περίπτωση χρήσης για να υλοποιηθεί πρώτη. Αυτή δεν ήταν άλλη από την κράτηση ενός ραντεβού από τον πελάτη. Επιλέχθηκε αυτή η περίπτωση χρήσης γιατί με αυτόν τον τρόπο θα καθορίζονταν εν μέρη και η αρχιτεκτονική του συστήματος καθώς αυτό θα εξελισσόταν σταδιακά με την ολοκλήρωση και των υπόλοιπων περιπτώσεων χρήσης.
|
||||
|
@ -90,10 +69,10 @@ public function find_record_id($admin) {
|
|||
Εδώ θα χρειαστεί να αναφερθεί ότι όλες οι κλήσεις AJAX έχουν μεταφερθεί σε μια κλάση controller, ξεχωριστά από τον κύριο controller του backend για να είναι καλύτερα οργανωμένες. Αν μελλοντικά ο αριθμός τους και η πολυπλοκότητα τους αυξηθεί τότε θα χρειαστεί να διαιρεθούν ξανά για να μπορέσουν να συντηρούνται πιο εύκολα.
|
||||
|
||||
%% ==================================================
|
||||
%% ΑΝΑΛΥΣΗ ΒΑΣΙΚΩΝ ΑΛΓΟΡΙΘΜΩΝ
|
||||
%% ΠΕΡΙΓΡΑΦΗ ΒΑΣΙΚΩΝ ΑΛΓΟΡΙΘΜΩΝ
|
||||
%% ==================================================
|
||||
\section{Ανάλυση Βασικών Αλγορίθμων}
|
||||
Σε αυτήν την ενότητα θα γίνει ανάλυση κάποιων βασικών αλγορίθμων που αποτελούν κρίσιμα τμήματα για την λειτουργία του συστήματος. Η περιγραφή θα γίνει σχολιάζοντας τα τμήματα κώδικα που απαρτίζουν αυτούς τους αλγορίθμους.
|
||||
\section{Περιγραφή Βασικών Αλγορίθμων}
|
||||
Σε αυτήν την ενότητα θα γίνει ανάλυση κάποιων βασικών αλγορίθμων που αποτελούν κρίσιμα τμήματα για την λειτουργία του συστήματος. Η περιγραφή θα γίνει σχολιάζοντας τα τμήματα κώδικα που απαρτίζουν αυτούς τους αλγορίθμους. Στην επόμενη ενότητα παρέχονται κάποια σχεδιαγράμματα τα οποία μπορούν να βοηθήσουν στην κατανόηση των αλγορίθμων αυτών.
|
||||
|
||||
\subsection{Πλήρης Συγχρονισμός Google Calendar}
|
||||
Η διαδικασία του πλήρη συγχρονισμού των ραντεβού με το Google Calendar αποτελεί ένας από τους κυριότερους αλγορίθμους του Easy!Appointments. Η πολυπλοκότητα της διαδικασίας συγχρονισμού δεδομένων κατέστησαν την υλοποίηση αυτού του τμήματος κώδικα αρκετά ενδιαφέρον και το αποτέλεσμα κατάφερε να καλύψει τις αρχικές απαιτήσεις. Μπορεί μελλοντικά να υπάρξουν βελτιώσεις στον κώδικα, αλλά την συγκεκριμένη στιγμή ο αλγόριθμος λειτουργεί επιτυχώς και συγχρονίζει τα ραντεβού του συστήματος με τα συμβάντα που έχει περάσει ο χρήστης στο Google Calendar με επιτυχία.
|
||||
|
@ -102,25 +81,58 @@ public function find_record_id($admin) {
|
|||
|
||||
Η μέθοδος αυτή καλείται κάθε φορά που πρέπει να τρέξει ο αλγόριθμος συγχρονισμού για έναν πάροχο υπηρεσιών. Στο πρώτο μέρος του κώδικα ελέγχεται αν ο χρήστης έχει τα δικαιώματα να τρέξει αυτήν την μέθοδο και αν έχει δοθεί το αναγνωριστικό της εγγραφής του πάροχου. Έπειτα φορτώνονται τα απαραίτητα models και γίνεται η λήψη των πληροφοριών του πάροχου από την βάση (γραμμές 17 - 31).
|
||||
|
||||
Για να συνεχιστεί η διαδικασία θα πρέπει να ελεγχθεί αν ο πάροχος έχει ενεργό τον συγχρονισμό με το Google Calendar. Αυτό είναι απαραίτητο διότι για να χρησιμοποιηθεί το Google Calendar API
|
||||
Για να συνεχιστεί η διαδικασία θα πρέπει να ελεγχθεί αν ο πάροχος έχει ενεργό τον συγχρονισμό με το Google Calendar. Αν η επιλογή αυτή είναι ενεργή τότε ο αλγόριθμος χρησιμοποιεί το token του πάροχου για να πιστοποιήσει την χρήση των δεδομένων του στο Google Calendar (γραμμές 34 - 44).
|
||||
|
||||
Για να γίνει εξοικονόμηση κλήσεων αλλά και να μειωθεί ο χρόνος διεκπεραίωσης του αλγορίθμου συγχρονισμού το χρονικό διάστημα μέσα στο οποίο θα συγχρονισθούν τα δεδομένα περιορίζεται στο εύρος που έχει τεθεί ως ρύθμιση για τον κάθε χρήστη πάροχο (προεπιλεγμένη τιμή 5 ημέρες στο παρελθόν και 5 στο μέλλον). Αυτό είναι το χρονικό διάστημα στο οποίο θα ελεγχθούν όλα τα δεδομένα και από τα δύο συστήματα και θα συντονιστούν έτσι ώστε να είναι τα ίδια (γραμμές 48 - 55).
|
||||
|
||||
Το επόμενο κομμάτι κώδικα αφού πρώτα λάβει τα ραντεβού από την βάση δεδομένων του Easy!Appointments, εξετάζει τις εγγραφές μια προς μια για το αν έχουν συγχρονιστεί με το Google Calendar. Εδώ υπάρχουν οι εξής περιπτώσεις:
|
||||
\begin{enumerate}
|
||||
\item Το ραντεβού δεν έχει ακόμα συγχρονιστεί οπότε θα πρέπει να προστεθεί στο Google Calendar (γραμμές 86-90).
|
||||
\item Το ραντεβού είναι συγχρονισμένο και πρέπει να ελεγχθεί αν υπάρχουν διαφορές με το συμβάν που είναι καταχωρημένο στο Google Calendar. Αν ναι τότε αυτό σημαίνει ότι ο χρήστης έχει αλλάξει τα στοιχεία του συμβάντος στο Google Calendar και η εγγραφή του ραντεβού στο Easy!Appointments θα πρέπει να ενημερωθεί (γραμμές 94 - 117).
|
||||
\item Το ραντεβού είναι συγχρονισμένο αλλά δεν έχει βρεθεί στο Google Calendar. Εφόσον δεν έχει βρεθεί η εγγραφή σημαίνει ότι ο χρήστης την έχει διαγράψει από το Google Calendar και έτσι θα πρέπει να διαγραφεί και από το Easy!Appointments (γραμμές 122 - 123).
|
||||
\end{enumerate}
|
||||
Με το πέρας αυτού του τμήματος κώδικα όλα τα ραντεβού του Easy!Appointments θα πρέπει να έχουν συγχρονιστεί με το Google Calendar.
|
||||
|
||||
Υπάρχουν όμως συμβάντα στην υπηρεσία της Google τα οποία μπορεί να έχουν προστεθεί απευθείας στο Google Calendar και να μην υπάρχουν στο Easy!Appointments. Σε αυτήν την περίπτωση θα πρέπει να ανιχνευθούν και να εξεταστούν όλα τα συμβάντα που αντιστοιχούν στην χρονική περίοδο συγχρονισμού (5 ημέρες πριν και 5 ημέρες μετά την τρέχουσα ημερομηνία) και να ελεγχθεί αν υπάρχει κάποιο συμβάν που δεν είναι συγχρονισμένο.
|
||||
|
||||
Αυτήν την εργασία αναλαμβάνει το επόμενο κομμάτι κώδικα το οποίο χρησιμοποιώντας την βιβλιοθήκη Google API μπορεί να διαβάσει τα συμβάντα τα οποία βρίσκονται στο Google Calendar. Η διαδικασία ξεκινάει με την λήψη αυτών των συμβάντων τα οποία στην συνέχεια εξετάζονται ένα προς ένα για το αν υπάρχουν στο Easy!Appointments. Αν όχι τότε προστίθενται και συγχρονίζονται και στα δύο συστήματα και έτσι διασφαλίζεται η ακεραιότητα των δεδομένων και στα δύο συστήματα (γραμμές 129 - 152).
|
||||
|
||||
\subsection{Υπολογισμός Διαθέσιμων Ωρών Πάροχου}
|
||||
Ένα κομβικό σημείο στον κώδικα της εφαρμογής είναι ο υπολογισμός των διαθέσιμων ωρών ενός πάρoχου, στις οποίες μπορεί ένας πελάτης να κλείσει ένα ραντεβού για μια υπηρεσία, χωρίς να υπάρχει σύγκρουση με άλλα συμβάντα. Για να επιτευχθεί ο υπολογισμός αυτός χρειάζεται να γίνουν αρκετοί έλεγχοι έτσι ώστε τα αποτελέσματα να είναι σωστά και να μην δημιουργούνται προβλήματα με τα πλάνα των πάροχων υπηρεσιών. Η διαδικασία χωρίζεται σε δύο μεθόδους με την πρώτη να υπολογίζει τα ελεύθερα χρονικά διαστήματα του πάροχου και την δεύτερη να υπολογίζει τις ακριβείς ώρες στις οποίες θα μπορεί ο πελάτης να κλείσει ραντεβού.
|
||||
|
||||
\lstinputlisting{snippets/provider_available_periods.php}
|
||||
|
||||
Το πρώτο πράγμα που πρέπει να γίνει είναι η λήψη του πλάνου εργασίας του πάροχου καθώς και των ήδη καταχωρημένων ραντεβού για την επιλεγμένη ημερομηνία. Επίσης υπάρχει και η περίπτωση να πρέπει να αποκλειστούν κάποια ραντεβού κατά τον υπολογισμό των διαθέσιμων ωρών οπότε αν έχουν οριστεί τέτοιες εγγραφές δεν λαμβάνονται υπόψιν στον υπολογισμό. Αυτή η επιλογή είναι απαραίτητη όταν χρειάζεται ο πελάτης να επεξεργαστεί ένα ήδη κρατημένο ραντεβού το οποίο δεν θα πρέπει να εμφανίζει ως δεσμευμένη την ώρα που αντιστοιχεί το ίδιο στο πλάνο του πάροχου. Τα στοιχεία αυτά θα χρησιμοποιηθούν έτσι ώστε τα διαθέσιμα διαστήματα που θα υπολογιστούν να αντιπροσωπεύουν τον χρόνο στον οποίο ο πάροχος θα είναι διαθέσιμος (γραμμές 23 - 48).
|
||||
|
||||
Έπειτα θα διαχωριστούν τα ελεύθερα χρονικά διαστήματα του πάροχου από τα διαλείμματα και τα ήδη καταχωρημένα ραντεβού. Αρχικά για την επιλεγμένη ημέρα του ραντεβού ελέγχονται αν υπάρχουν καθόλου διαλείμματα. Αν ναι, τότε τα διαθέσιμα διαστήματα χωρίζονται μεταξύ των διαλειμμάτων του πάροχου (γραμμές 54 - 84) και παράγονται νέα χρονικά διαστήματα. Στην συνέχεια λαμβάνονται υπόψιν τα ραντεβού που έχουν ήδη κρατηθεί. Τα διαθέσιμα χρονικά διαστήματα του πάροχου θα διασπαστούν ξανά μεταξύ των ραντεβού αυτών και έτσι θα ολοκληρωθεί η διαδικασία του υπολογισμού (γραμμές 91 - 149). Αν την επιλεγμένη ημερομηνία ο πάροχος δεν έχει κανένα ραντεβού τότε δεν πραγματοποιείται καμία επιπλέον διάσπαση και το αποτέλεσμα επιστρέφεται όπως είναι (γραμμές 187 - 188). Στην επόμενη μέθοδο ο πίνακας που περιέχει τα διαστήματα θα χρησιμοποιηθεί για να υπολογιστούν οι ακριβείς διαθέσιμες ώρες στις οποίες θα μπορεί ο πελάτης να κλείσει κάποιο ραντεβού.
|
||||
|
||||
\lstinputlisting{snippets/provider_appointment_hours.php}
|
||||
|
||||
Η δεύτερη μέθοδος αποτελεί απάντηση σε κλήση της JavaScript με χρήση της τεχνικής AJAX. Όταν ο client καλεί αυτήν την μέθοδο, παρέχει τα στοιχεία του πάροχου, την διάρκεια της επιλεγμένης υπηρεσίας (σε λεπτά) και το αν ο χρήστης επεξεργάζεται το συγκεκριμένο ραντεβού ή όχι (παράμετρος manage\_mode). Αυτό που εκτελείται αρχικά είναι η λήψη των ελεύθερων χρονικών διαστημάτων του πάροχου χρησιμοποιώντας την προαναφερθέντα μέθοδο get\_provider\_available\_time\_periods (γραμμές 30 - 36).
|
||||
|
||||
Έπειτα θα υπολογιστούν οι διαθέσιμες ώρες στις οποίες θα μπορέσει ο χρήστης να κλείσει ραντεβού. Αυθαίρετα και για λόγους ευχρηστίας έχει τεθεί το χρονικό διάστημα μεταξύ των ελεύθερων ωρών να είναι τα 15 λεπτά. Αυτό που κάνει το συγκεκριμένο κομμάτι κώδικα είναι ουσιαστικά ο διαχωρισμός των ελεύθερων χρονικών διαστημάτων του πάροχου σε ώρες τις οποίες χωρίζουν 15 λεπτά τουλάχιστον και οι οποίες μπορούν να χωρέσουν την διάρκεια της υπηρεσίας για την οποία ενδιαφέρεται ο πελάτης, πριν την λήξη του διαθέσιμου χρονικού διαστήματος (γραμμές 43 - 76).
|
||||
|
||||
Στο τελευταίο μέρος αυτής της μεθόδους ελέγχεται αν η επιλεγμένη ημερομηνία αντιστοιχεί στην σημερινή και αν αυτό ισχύει αφαιρούνται οι παρελθοντικές διαθέσιμες ώρες έτσι ώστε να μην μπορεί ο πελάτης να κλείσει ραντεβού σε μια παρελθοντική χρονική στιγμή. Το σύστημα στο frontend δεν επιτρέπει ούτως ή άλλος την επιλογή παρελθοντικής ημερομηνίας, αλλά απαιτείται στην συγκεκριμένη περίπτωση να ελεγχθούν οι παρελθοντικές ώρες του ραντεβού. Επίσης είναι σημαντικό να αναφερθεί ότι η εφαρμογή παρέχει μια παράμετρο η οποία ορίζει το χρονικό διάστημα που θα πρέπει να χωρίζει ένα ραντεβού από την ώρα που αυτό γίνεται κράτηση ή επεξεργάζεται. Ο λόγος γίνεται για την ρύθμιση του συστήματος με το όνομα "book_advance_timeout" η οποία μετράται σε λεπτά και λαμβάνεται υπόψιν στον υπολογισμό των διαθέσιμων ωρών.
|
||||
|
||||
%% ==================================================
|
||||
%% ΔΙΑΓΡΑΜΜΑΤΑ ΚΩΔΙΚΑ
|
||||
%% ==================================================
|
||||
\section{Διαγράμματα Κώδικα}
|
||||
Σε αυτήν την ενότητα θα παρατεθούν κάποια διαγράμματα κώδικα τα οποία θα βοηθήσουν τον αναγνώστη στην κατανόηση της λειτουργίας του συστήματος και στον τρόπο με τον οποίο διεκπεραιώνονται οι εργασίες που απαιτούνται στην εκάστοτε περίπτωση χρήσης.
|
||||
Σε αυτήν την ενότητα θα παρατεθούν κάποια διαγράμματα κώδικα τα οποία θα βοηθήσουν τον αναγνώστη στην κατανόηση της λειτουργίας του συστήματος και στον τρόπο με τον οποίο διεκπεραιώνονται οι εργασίες που απαιτούνται στην εκάστοτε περίπτωση χρήσης. Τα διαγράμματα αυτά ακολουθούν το σχεδιαστικό πρότυπο UML το οποίο αποτελεί την πιο δημοφιλής γλώσσα μοντελοποίησης εδώ και αρκετά χρόνια.
|
||||
|
||||
Η εφαρμογή που χρησιμοποιήθηκε για τον σχεδιασμό των διαγραμμάτων αυτών είναι η draw.io και πρόκειται για μια διαδικτυακή πλατφόρμα με την οποία μπορούν να γίνουν σχεδιαγράμματα πολλών διαφορετικών τύπων. Το draw.io είναι δωρεάν προς χρήση και μπορεί να βρεθεί στην διεύθυνση http://www.draw.io.
|
||||
|
||||
\subsection{Διαγράμματα Ροής}
|
||||
Τα διαγράμματα ροής δείχνουν τον τρόπο με τον οποίο λειτουργούν οι διαδικασίες μεταξύ τους. Σε αυτά είναι εύκολο να διακριθούν με ποιον τρόπο επικοινωνούν τα διάφορα συστήματα μεταξύ τους και την πορεία των δεδομένων μέχρι αυτά να φτάσουν τον τελικό προορισμό τους.
|
||||
Τα διαγράμματα ροής δείχνουν τον τρόπο και την σειρά με την οποία λειτουργούν οι διεργασίες και τα αντικείμενα μεταξύ τους για την διεκπεραίωση ενός σκοπού. Σε αυτά είναι εύκολο να διακριθούν ποιοι ηθοποιοί, αντικείμενα, διεπαφές και μέθοδοι αλληλεπιδρούν έτσι ώστε τα δεδομένα που χρειάζονται για την εργασία να παραχθούν επιτυχώς και να φτάσουν ακέραια στον προορισμό τους. Σε αυτά τα διαγράμματα ο χρονικός προσδιορισμός της κάθε αλληλεπίδρασης είναι εμφανής και πολύ σημαντικός για να μπορέσει ο προγραμματιστής να καταλάβει με ποια σειρά θα πρέπει να πορευτεί η εκτέλεση έτσι ώστε αυτός να καταλήξει σε σωστό αποτέλεσμα. Συνήθως τα διαγράμματα ροής συγχέονται με το σενάριο κάποιας περίπτωσης χρήσης αλλά μπορούν να διασπαστούν και σε μικρότερα τμήματα τα οποία να επικεντρώνουν στα σημεία που είναι πιο σημαντικά.
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{figure}%% [Η] αυτή η εντολή θα τοποθετήσει το διάγραμμα ακριβώς σε αυτό το σημείο. Το latex όμως πάντα προσπαθεί να αφήσει όσο λιγότερα κενό χόρο γίνεται και έτσι τα διαγράμματα δεν θα εμφανιστούν με την σειρά που γράφονται στον κώδικα.
|
||||
\centering
|
||||
\includegraphics[width=150mm]{images/sd-save-appointment.png}
|
||||
\caption{Στο διάγραμμα ροής εμφανίζεται η διαδικασία που εκτελείται για την αποθήκευση ενός ραντεβού μετά την επιτυχή καταχώρηση του από τον πελάτη.}
|
||||
\label{sd-save-appointment}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=150mm]{images/sd-sync-appointment.png}
|
||||
\caption{Στο διάγραμμα ροής εμφανίζεται η διαδικασία με την οποία πραγματοποιείται η προσθήκη ενός ραντεβού στο Google Calendar.}
|
||||
|
@ -128,33 +140,47 @@ public function find_record_id($admin) {
|
|||
\end{figure}
|
||||
|
||||
\subsection{Διαγράμματα Δραστηριότητας}
|
||||
Τα διαγράμματα δραστηριότητας αποτελούν γραφικές παραστάσεις της δραστηριότητας του συστήματος ανάλογα με τις αποφάσεις που λαμβάνονται μέσα από τον κώδικα. Σε αυτά τα διαγράμματα μπορούν να φανούν τα σημεία στα οποία υπάρχουν βρόγχοι επανάληψης, τα σημεία όπου μπορούν να συμβούν λογικά σφάλματα (οι απαιτήσεις για συνέχιση της εκτέλεσης δεν πληρούνται) όπως και επίσης τις διαδικασίες που τρέχουν ταυτόχρονα και το πότε γίνεται αυτό.
|
||||
Τα διαγράμματα δραστηριότητας αποτελούν γραφικές παρουσιάσεις της δραστηριότητας του που ακολουθεί το σύστημα ανάλογα με τις αποφάσεις που λαμβάνονται μέσα από τον κώδικα. Σε αυτά τα διαγράμματα μπορούν να φανούν τα σημεία στα οποία υπάρχουν βρόγχοι επανάληψης, τα σημεία όπου μπορούν να συμβούν λογικά σφάλματα (οι απαιτήσεις για συνέχιση της εκτέλεσης δεν πληρούνται) όπως και επίσης τις διαδικασίες που τρέχουν ταυτόχρονα και σε ποιο σημείο γίνεται αυτό. Κατά κύριο λόγο τα διαγράμματα δραστηριότητας δείχνει την συνολική ροή του ελέγχου μέσα από την εκτέλεση μιας συγκεκριμένης διαδικασίας.
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=100mm]{images/ad-book-appointment.png}
|
||||
\includegraphics[width=90mm]{images/ad-book-appointment.png}
|
||||
\caption{Αναπαράσταση της διαδικασίας κράτησης ραντεβού.}
|
||||
\label{ad-book-appointment}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=100mm]{images/ad-install-application.png}
|
||||
\includegraphics[width=70mm]{images/ad-install-application.png}
|
||||
\caption{Αναπαράσταση της διαδικασίας εγκατάστασης της εφαρμογής.}
|
||||
\label{ad-install-application}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Διαγράμματα Κλάσεων}
|
||||
Στην τεχνολογία λογισμικού, τα διαγράμματα κλάσεων περιγράφουν την στατική δομή ενός συστήματος δείχνοντας τις κλάσεις, τις ιδιότητες, τις λειτουργίες και τις σχέσεις μεταξύ των αντικειμένων. Το σχεδιαγράμματα αυτά είναι τα βασικότερα για έναν προγραμματιστή διότι μπορεί άμεσα να πληροφορηθεί σχετικά με την δομή του κώδικα και με ποιόν τρόπο θα πρέπει να συνεχιστεί η διαδικασία της υλοποίησης.
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=70mm]{images/ad-sync-appointments.png}
|
||||
\caption{Αναπαράσταση της διαδικασίας συγχρονισμού ραντεβού μεταξύ του Easy!Appointments και του Google Calendar. Ο αλγόριθμος συγχρονισμού είναι αμφίδρομος.}
|
||||
\label{ad-sync-appointments}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=70mm]{images/ad-provider-available-hours.png}
|
||||
\caption{Αναπαράσταση της διαδικασίας υπολογισμού των διαθέσιμων ωρών για κράτηση ραντεβού από τον πελάτη.}
|
||||
\label{ad-provider-available-hours}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Διαγράμματα Κλάσεων}
|
||||
Στην τεχνολογία λογισμικού, τα διαγράμματα κλάσεων περιγράφουν την στατική δομή ενός συστήματος δείχνοντας τις κλάσεις, τις ιδιότητες, τις λειτουργίες και τις σχέσεις μεταξύ των αντικειμένων. Το σχεδιαγράμματα αυτά είναι τα βασικότερα για έναν προγραμματιστή διότι μπορεί άμεσα να πληροφορηθεί σχετικά με την δομή του κώδικα και με ποιόν τρόπο θα πρέπει να συνεχιστεί η διαδικασία της υλοποίησης. Επίσης είναι εμφανές και οι αρχιτεκτονικές επιλογές που έχουν γίνει καθώς κάθε σχεδιαστικό πρότυπο που πρέπει να έχει ο κώδικας μπορεί να διακριθεί και να περιγραφή σε αυτά τα διαγράμματα. Καλή πρακτική είναι πάντα ένα διάγραμμα να περιέχει μόνο την ουσία οπότε στο υποκεφάλαιο αυτό εμφανίζονται διαγράμματα κλάσης τα οποία δείχνουν κάποιες σχεδιαστικές επιλογές που έχουν γίνει στην εφαρμογή.
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=150mm]{images/cd-backend-users.png}
|
||||
\caption{Στο διάγραμμα αυτό φαίνεται η τρόπος με τον οποίον υλοποιείται η λειτουργικότητα της σελίδας διαχείρισης των χρηστών του συστήματος μέσω της JavaScript. Η κάθε ενότητα διαχείρισης (διαχειριστές, πάροχοι και γραμματείς) έχουν την δικιά τους κλάση, η οποία καθορίζει με ποιόν τρόπο θα χρειαστεί να ανταποκριθεί η εφαρμογή.}
|
||||
\label{cd-backend-users}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=150mm]{images/cd-backend-settings.png}
|
||||
\caption{Σε αυτό το διάγραμμα κλάσεων φαίνεται οι κλάσεις που συμμετέχουν στον JavaScript κώδικα των κεντρικών ρυθμίσεων της εφαρμογής. Οι κάθε μια κλάση αντιπροσωπεύει την λειτουργία μιας κατηγορίας ρυθμίσεων και μαζί χρησιμοποιούνται για την σωστή λειτουργία της σελίδας.}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
\item [Γραμματέας] Ο γραμματέας είναι ένας χρήστης ο οποίος μπορεί να διαχειριστεί τα ραντεβού και τους πελάτες του συστήματος για συγκεκριμένους πάροχους υπηρεσιών. Το σε ποιους πάροχους αντιστοιχεί ο κάθε χρήστης γραμματέας ορίζεται από τον διαχειριστή στο περιβάλλον ρυθμίσεων της εφαρμογής.
|
||||
|
||||
\item [Πλάνο Πάροχου] Από την στιγμή που κλείνονται ραντεβού σε έναν πάροχο υπηρεσιών το ημερολογιακό του πλάνο αρχίζει να γεμίζει από χρονικά διαστήματα, τα οποία είναι δεσμευμένα και αντιπροσωπεύουν συναντήσεις με τους πελάτες. Εκτός αυτού υπάρχει και η δυνατότητα να τεθεί ένα ανενεργό χρονικό διάστημα, στο οποίο ο συγκεκριμένος πάροχος δεν θα είναι διαθέσιμος έτσι ώστε να μην μπορούν οι πελάτες να κλείνουν ραντεβού σε αυτό το διάστημα. Αυτό το πλάνο μπορεί να συγχρονιστεί με το Google Calendar έτσι ώστε να είναι προσβάσιμο και από άλλες υπηρεσίες.
|
||||
|
||||
\item [Easy!Appointments] Με την ονομασία Easy!Appointments θα γίνεται αναφορά στο σύστημα που υλοποιήθηκε.
|
||||
\end{description}
|
||||
\end{Definitions}
|
||||
|
||||
|
|
30
doc/thesis/snippets/find_record_id.php
Normal file
30
doc/thesis/snippets/find_record_id.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* Find the database record id of an admin user.
|
||||
*
|
||||
* @param array $admin Contains the admin data. The 'email'
|
||||
* value is required in order to find the record id.
|
||||
* @return int Returns the record id
|
||||
* @throws Exception When the 'email' value is not present
|
||||
* on the $admin array.
|
||||
*/
|
||||
public function find_record_id($admin) {
|
||||
if (!isset($admin['email'])) {
|
||||
throw new Exception('Admin email was not provided: '
|
||||
. print_r($admin, TRUE));
|
||||
}
|
||||
|
||||
$result = $this->db
|
||||
->select('ea_users.id')
|
||||
->from('ea_users')
|
||||
->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'inner')
|
||||
->where('ea_users.email', $admin['email'])
|
||||
->where('ea_roles.slug', DB_SLUG_ADMIN)
|
||||
->get();
|
||||
|
||||
if ($result->num_rows() == 0) {
|
||||
throw new Exception('Could not find admin record id.');
|
||||
}
|
||||
|
||||
return intval($result->row()->id);
|
||||
}
|
110
doc/thesis/snippets/provider_appointment_hours.php
Normal file
110
doc/thesis/snippets/provider_appointment_hours.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
/**
|
||||
* [AJAX] Get the available appointment hours for the given date.
|
||||
*
|
||||
* This method answers to an AJAX request. It calculates the
|
||||
* available hours for thegiven service, provider and date.
|
||||
*
|
||||
* @param numeric $_POST['service_id'] The selected service's
|
||||
* record id.
|
||||
* @param numeric $_POST['provider_id'] The selected provider's
|
||||
* record id.
|
||||
* @param string $_POST['selected_date'] The selected date of
|
||||
* which the available hours we want to see.
|
||||
* @param numeric $_POST['service_duration'] The selected service
|
||||
* duration in minutes.
|
||||
* @param string $_POST['manage_mode'] Contains either 'true' or
|
||||
* 'false' and determines the if current user is managing an already
|
||||
* booked appointment or not.
|
||||
* @return Returns a json object with the available hours.
|
||||
*/
|
||||
public function ajax_get_available_hours() {
|
||||
$this->load->model('providers_model');
|
||||
$this->load->model('appointments_model');
|
||||
$this->load->model('settings_model');
|
||||
|
||||
try {
|
||||
// If manage mode is TRUE then the following we should not
|
||||
// consider the selected appointment when calculating the
|
||||
// available time periods of the provider.
|
||||
$exclude_appointments = ($_POST['manage_mode'] === 'true')
|
||||
? array($_POST['appointment_id'])
|
||||
: array();
|
||||
|
||||
$empty_periods = $this->get_provider_available_time_periods(
|
||||
$_POST['provider_id'], $_POST['selected_date'],
|
||||
$exclude_appointments);
|
||||
|
||||
// Calculate the available appointment hours for the given
|
||||
// date. The empty spaces are broken down to 15 min and if
|
||||
// the service fit in each quarter then a new available hour
|
||||
// is added to the "$available_hours" array.
|
||||
|
||||
$available_hours = array();
|
||||
|
||||
foreach ($empty_periods as $period) {
|
||||
$start_hour = new DateTime($_POST['selected_date']
|
||||
. ' ' . $period['start']);
|
||||
$end_hour = new DateTime($_POST['selected_date']
|
||||
. ' ' . $period['end']);
|
||||
|
||||
$minutes = $start_hour->format('i');
|
||||
|
||||
if ($minutes % 15 != 0) {
|
||||
// Change the start hour of the current space in
|
||||
// order to be on of the following: 00, 15, 30, 45.
|
||||
if ($minutes < 15) {
|
||||
$start_hour->setTime($start_hour->format('H'), 15);
|
||||
} else if ($minutes < 30) {
|
||||
$start_hour->setTime($start_hour->format('H'), 30);
|
||||
} else if ($minutes < 45) {
|
||||
$start_hour->setTime($start_hour->format('H'), 45);
|
||||
} else {
|
||||
$start_hour->setTime($start_hour->format('H') + 1, 00);
|
||||
}
|
||||
}
|
||||
|
||||
$current_hour = $start_hour;
|
||||
$diff = $current_hour->diff($end_hour);
|
||||
|
||||
while (($diff->h * 60 + $diff->i)
|
||||
> intval($_POST['service_duration'])) {
|
||||
$available_hours[] = $current_hour->format('H:i');
|
||||
$current_hour->add(new DateInterval("PT15M"));
|
||||
$diff = $current_hour->diff($end_hour);
|
||||
}
|
||||
}
|
||||
|
||||
// If the selected date is today, remove past hours. It is
|
||||
// important include the timeout before booking that is set
|
||||
// in the backoffice the system. Normally we might want the
|
||||
// customer to book an appointment that is at least half or
|
||||
// one hour from now. The setting is stored in minutes.
|
||||
if (date('m/d/Y', strtotime($_POST['selected_date']))
|
||||
== date('m/d/Y')) {
|
||||
if ($_POST['manage_mode'] === 'true') {
|
||||
$book_advance_timeout = 0;
|
||||
} else {
|
||||
$book_advance_timeout =
|
||||
$this->settings_model->get_setting('book_advance_timeout');
|
||||
}
|
||||
|
||||
foreach($available_hours as $index => $value) {
|
||||
$available_hour = strtotime($value);
|
||||
$current_hour = strtotime('+' . $book_advance_timeout
|
||||
. ' minutes', strtotime('now'));
|
||||
if ($available_hour <= $current_hour) {
|
||||
unset($available_hours[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$available_hours = array_values($available_hours);
|
||||
echo json_encode($available_hours);
|
||||
|
||||
} catch(Exception $exc) {
|
||||
echo json_encode(array(
|
||||
'exceptions' => array(exceptionToJavaScript($exc))
|
||||
));
|
||||
}
|
||||
}
|
192
doc/thesis/snippets/provider_available_periods.php
Normal file
192
doc/thesis/snippets/provider_available_periods.php
Normal file
|
@ -0,0 +1,192 @@
|
|||
<?php
|
||||
/**
|
||||
* Get an array containing the free time periods (start - end) of a
|
||||
* selected date.
|
||||
*
|
||||
* This method is very important because there are many cases where
|
||||
* the system needs to know when a provider is avaible for an
|
||||
* appointment. This method will return an array that belongs to the
|
||||
* selected date and contains values that have the start and the end
|
||||
* time of an available time period.
|
||||
*
|
||||
* @param numeric $provider_id The provider's record id.
|
||||
* @param string $selected_date The date to be checked (MySQL
|
||||
* formatted string).
|
||||
* @param array $exclude_appointments This array contains the ids of
|
||||
* the appointments that will not be taken into consideration when
|
||||
* the available time periods are calculated.
|
||||
* @return array Returns an array with the available time periods of
|
||||
* the provider.
|
||||
*/
|
||||
private function get_provider_available_time_periods($provider_id,
|
||||
$selected_date, $exclude_appointments = array()) {
|
||||
$this->load->model('appointments_model');
|
||||
$this->load->model('providers_model');
|
||||
|
||||
// Get the provider's working plan and reserved appointments.
|
||||
$working_plan = json_decode($this->providers_model
|
||||
->get_setting('working_plan', $provider_id), true);
|
||||
|
||||
$where_clause = array(
|
||||
'DATE(start_datetime)' =>
|
||||
date('Y-m-d', strtotime($selected_date)),
|
||||
'id_users_provider' => $provider_id
|
||||
);
|
||||
|
||||
$reserved_appointments =
|
||||
$this->appointments_model->get_batch($where_clause);
|
||||
|
||||
// Sometimes it might be necessary to not take into account some
|
||||
// appointment records in order to display what the providers'
|
||||
// available time periods would be without them.
|
||||
foreach ($exclude_appointments as $excluded_id) {
|
||||
foreach ($reserved_appointments as $index => $reserved) {
|
||||
if ($reserved['id'] == $excluded_id) {
|
||||
unset($reserved_appointments[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the empty spaces on the plan. The first split between
|
||||
// the plan is due to a break (if exist). After that every
|
||||
// reserved appointment is considered to be a taken space in the
|
||||
// plan.
|
||||
$selected_date_working_plan =
|
||||
$working_plan[strtolower(date('l', strtotime($selected_date)))];
|
||||
$available_periods_with_breaks = array();
|
||||
|
||||
if (isset($selected_date_working_plan['breaks'])) {
|
||||
foreach($selected_date_working_plan['breaks'] as $index=>$break){
|
||||
// Split the working plan to available time periods that do not
|
||||
// contain the breaks in them.
|
||||
$last_break_index = $index - 1;
|
||||
|
||||
if (count($available_periods_with_breaks) === 0) {
|
||||
$start_hour = $selected_date_working_plan['start'];
|
||||
$end_hour = $break['start'];
|
||||
} else {
|
||||
$start_hour = $selected_date_working_plan
|
||||
['breaks'][$last_break_index]['end'];
|
||||
$end_hour = $break['start'];
|
||||
}
|
||||
|
||||
$available_periods_with_breaks[] = array(
|
||||
'start' => $start_hour,
|
||||
'end' => $end_hour
|
||||
);
|
||||
}
|
||||
|
||||
// Add the period from the last break to the end of the day.
|
||||
$available_periods_with_breaks[] = array(
|
||||
'start' =>$selected_date_working_plan['breaks'][$index]['end'],
|
||||
'end' => $selected_date_working_plan['end']
|
||||
);
|
||||
}
|
||||
|
||||
// Break the empty periods with the reserved appointments.
|
||||
$available_periods_with_appointments = array();
|
||||
|
||||
if (count($reserved_appointments) > 0) {
|
||||
|
||||
foreach($available_periods_with_breaks as $period) {
|
||||
|
||||
foreach($reserved_appointments as $index=>$reserved) {
|
||||
$appointment_start =
|
||||
date('H:i', strtotime($reserved['start_datetime']));
|
||||
$appointment_end =
|
||||
date('H:i', strtotime($reserved['end_datetime']));
|
||||
$period_start =
|
||||
date('H:i', strtotime($period['start']));
|
||||
$period_end =
|
||||
date('H:i', strtotime($period['end']));
|
||||
|
||||
if ($period_start <= $appointment_start
|
||||
&& $period_end >= $appointment_end) {
|
||||
// We need to check whether another appointment fits
|
||||
// in the current time period. If this happens, then
|
||||
// we need to consider the whole appointment time as
|
||||
// one, because the provider will not be available.
|
||||
foreach ($reserved_appointments as $tmp_appointment) {
|
||||
$appt_start = date('H:i',
|
||||
strtotime($tmp_appointment['start_datetime']));
|
||||
$appt_end = date('H:i',
|
||||
strtotime($tmp_appointment['end_datetime']));
|
||||
|
||||
if ($period_start < $appt_start
|
||||
&& $period_end > $appt_end) {
|
||||
if ($appointment_start > $appt_start) {
|
||||
$appointment_start = $appt_start;
|
||||
}
|
||||
|
||||
if ($appointment_end < $appt_end) {
|
||||
$appointment_end = $appt_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Current appointment is within the current
|
||||
// empty space. So we need to break the empty
|
||||
// space into two other spaces that don't include
|
||||
// the appointment.
|
||||
$new_period = array(
|
||||
'start' => $period_start,
|
||||
'end' => $appointment_start
|
||||
);
|
||||
|
||||
if (!in_array($new_period,
|
||||
$available_periods_with_appointments)) {
|
||||
$available_periods_with_appointments[] = $new_period;
|
||||
}
|
||||
|
||||
$new_period = array(
|
||||
'start' => $appointment_end,
|
||||
'end' => $period_end
|
||||
);
|
||||
|
||||
if (!in_array($new_period,
|
||||
$available_periods_with_appointments)) {
|
||||
$available_periods_with_appointments[] = $new_period;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Check if there are any other appointments
|
||||
// between this time space. If not, it is going
|
||||
// to be added as it is.
|
||||
$found = FALSE;
|
||||
|
||||
foreach ($reserved_appointments as $tmp_appointment) {
|
||||
$appt_start = date('H:i',
|
||||
strtotime($tmp_appointment['start_datetime']));
|
||||
$appt_end = date('H:i',
|
||||
strtotime($tmp_appointment['end_datetime']));
|
||||
|
||||
if ($period_start < $appt_start
|
||||
&& $period_end > $appt_end) {
|
||||
$found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// It is also necessary to check that this time
|
||||
// period doesn't already exist in the
|
||||
// "$empty_spaces_with_appointments" array.
|
||||
$empty_period = array(
|
||||
'start' => $period_start,
|
||||
'end' => $period_end
|
||||
);
|
||||
|
||||
$already_exist = in_array($empty_period,
|
||||
$available_periods_with_appointments);
|
||||
|
||||
if ($found === FALSE && $already_exist === FALSE) {
|
||||
$available_periods_with_appointments[] = $empty_period;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$available_periods_with_appointments =
|
||||
$available_periods_with_breaks;
|
||||
}
|
||||
|
||||
return $available_periods_with_appointments;
|
||||
}
|
Binary file not shown.
Loading…
Reference in a new issue