diff --git a/doc/thesis/includes/headers.tex b/doc/thesis/includes/headers.tex index e3b1678c..dcb9b9e0 100644 --- a/doc/thesis/includes/headers.tex +++ b/doc/thesis/includes/headers.tex @@ -1,16 +1,23 @@ \documentclass[oneside, 12pt]{book} + +%% ============================================================================ +%% ΟΡΙΣΜΟΣ ΤΩΝ PACKAGES ΠΟΥ ΘΑ ΧΡΗΣΙΜΟΠΟΙΗΘΟΥΝ +%% ============================================================================ \usepackage{thesis} \usepackage{tabularx} \usepackage{epsfig} \usepackage{float} - +\usepackage{listings} \usepackage{hyperref} \usepackage {color} + +%% ============================================================================ +%% ΡΥΘΜΙΣΗ ΤΩΝ HYPERLINKS +%% ============================================================================ \hypersetup {colorlinks} \definecolor{darkred}{rgb}{0.5,0,0} \definecolor{darkgreen}{rgb}{0,0.5,0} \definecolor{darkblue}{rgb}{0,0,0.5} - \hypersetup{ colorlinks, linkcolor=darkblue, @@ -19,7 +26,37 @@ citecolor=darkred } +%% ============================================================================ +%% PHP LISTINGS STYLE +%% http://tex.stackexchange.com/a/54687 +%% http://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings +%% http://en.wikibooks.org/wiki/LaTeX/Colors +%% ============================================================================ +\definecolor{dkgreen}{rgb}{0,.6,0} +\definecolor{dkblue}{rgb}{0,0,.6} +\definecolor{dkyellow}{cmyk}{0,0,.8,.3} +\definecolor{ltgrey}{RGB}{240,240,240} +\lstset{ + language = php, + basicstyle = \footnotesize\ttfamily, + keywordstyle = \color{dkblue}, + stringstyle = \color{red}, + identifierstyle = \color{dkgreen}, + commentstyle = \color{gray}, + emph =[1]{php}, + emphstyle =[1]\color{black}, + emph =[2]{if,and,or,else,public,function,try,catch}, + emphstyle =[2]\color{dkyellow}, + numbers = left, + tabsize = 2, + backgroundcolor = \color{ltgrey}, + extendedchars = true, + showspaces = false, + showstringspaces= false} + +%% ============================================================================ %% ΤΑ ΠΑΡΑΚΑΤΩ ΕΙΝΑΙ ΥΠΟΧΡΕΩΤΙΚΑ +%% ============================================================================ \renewcommand{\thesistitle}{Δημιουργία διαδικτυακού συστήματος συνατντήσεων (appointments) με χρήση Google Calendar PHP API} \renewcommand{\thesisauthor}{Αλέξανδρος Τσελεγγίδης (2503)} \renewcommand{\thesisauthorabbrv}{Α. Τσελεγγίδης} diff --git a/doc/thesis/includes/implementation.tex b/doc/thesis/includes/implementation.tex index d98e737a..a3629215 100644 --- a/doc/thesis/includes/implementation.tex +++ b/doc/thesis/includes/implementation.tex @@ -1,7 +1,10 @@ \chapter{Σχεδίαση \& Υλοποίηση} Σε αυτό το κεφάλαιο γίνεται ανάλυση του συστήματος στα επιμέρους μέρη και περιγράφεται η διαδικασία της υλοποίησης τους. Επεξηγούνται επίσης τα σημαντικότερα σημεία στον κώδικα και οι αλγόριθμοι που χρησιμοποιούνται για την επίλυση των κυριότερων λειτουργιών. Έχουν συμπεριληφθεί τμήματα κώδικα αλλά και διαγράμματα τα οποία βοηθούν στην κατανόηση των λύσεων που έχουν χρησιμοποιηθεί. -\subsection{Δεδομένα Συστήματος} +%% ================================================== +%% ΔΕΔΟΜΕΝΑ ΣΥΣΤΗΜΑΤΟΣ +%% ================================================== +\section{Δεδομένα Συστήματος} Το κυριότερο πρόβλημα που προσπαθεί να λύσει το σύστημα είναι η κράτηση και η διαχείριση ραντεβού από μια επιχείριση. Σε αυτήν την περίπτωση χρήσης έχει επικεντρωθεί η σχεδίαση και η υλοποίηση του συστήματος το οποίο περιέχει και άλλες δυνατότητες οι οποίες μπορούν όμως να θεωρηθούν λιγότερο σημαντικές. Έχοντας υπόψιν την έννοια "ραντεβού" ως την κύρια οντότητα της εφαρμογής, σχεδιάστηκε το παρακάτω μοντέλο το οποίο διευκρινίζει τις σχέσεις των υπόλοιπων οντοτήτων σε σχέση με το ραντεβού αλλά και μεταξύ τους. \begin{figure}[ht!] @@ -45,6 +48,9 @@ public function find_record_id($admin) { } \end{verbatim} +%% ================================================== +%% ΑΡΧΙΤΕΚΤΟΝΙΚΗ ΤΟΥ ΚΩΔΙΚΑ +%% ================================================== \section{Αρχιτεκτονική Του Κώδικα} Η εφαρμογή είναι γραμμένη χρησιμοποιώντας τις εξής τεχνολογίες: PHP, Javascript, HTML, CSS, MySQL. Εκτός αυτών έχουν χρησιμοποιηθεί και κάποια βοηθητικά εργαλεία τα οποία διευκολύνουν τον προγραμματιστή στο να πετύχει καλύτερο αποτέλεσμα σε μικρότερο χρόνο. Αυτά τα εργαλεία (frameworks) όπως έχουν αναφερθεί και σε προηγούμενο κεφάλαιο είναι τα CodeIgniter (PHP), jQuery (Javascript), Bootstrap (CSS + Javascript). @@ -63,6 +69,9 @@ public function find_record_id($admin) { \label{system-architecture} \end{figure} +%% ================================================== +%% ΥΛΟΠΟΙΗΣΗ ΤΟΥ ΣΥΣΤΗΜΑΤΟΣ +%% ================================================== \section{Υλοποίηση Του Συστήματος} Εφόσον ο αρχικός σχεδιασμός είχε ολοκληρωθεί ξεκίνησε η υλοποίηση της εφαρμογής με πρώτη εργασία τον σχεδιασμό της βάσης δεδομένων. Έχοντας ήδη σχεδιασμένο το domain model η δημιουργία του σχήματος της βάσης έγινε γρήγορα και διατηρήθηκε ως την ολοκλήρωση του έργου με μικρές προσθήκες όπου ήταν απαραίτητο. @@ -80,6 +89,24 @@ public function find_record_id($admin) { Εδώ θα χρειαστεί να αναφερθεί ότι όλες οι κλήσεις AJAX έχουν μεταφερθεί σε μια κλάση controller, ξεχωριστά από τον κύριο controller του backend για να είναι καλύτερα οργανωμένες. Αν μελλοντικά ο αριθμός τους και η πολυπλοκότητα τους αυξηθεί τότε θα χρειαστεί να διαιρεθούν ξανά για να μπορέσουν να συντηρούνται πιο εύκολα. +%% ================================================== +%% ΑΝΑΛΥΣΗ ΒΑΣΙΚΩΝ ΑΛΓΟΡΙΘΜΩΝ +%% ================================================== +\section{Ανάλυση Βασικών Αλγορίθμων} +Σε αυτήν την ενότητα θα γίνει ανάλυση κάποιων βασικών αλγορίθμων που αποτελούν κρίσιμα τμήματα για την λειτουργία του συστήματος. Η περιγραφή θα γίνει σχολιάζοντας τα τμήματα κώδικα που απαρτίζουν αυτούς τους αλγορίθμους. + +\subsection{Πλήρης Συγχρονισμός Google Calendar} +Η διαδικασία του πλήρη συγχρονισμού των ραντεβού με το Google Calendar αποτελεί ένας από τους κυριότερους αλγορίθμους του Easy!Appointments. Η πολυπλοκότητα της διαδικασίας συγχρονισμού δεδομένων κατέστησαν την υλοποίηση αυτού του τμήματος κώδικα αρκετά ενδιαφέρον και το αποτέλεσμα κατάφερε να καλύψει τις αρχικές απαιτήσεις. Μπορεί μελλοντικά να υπάρξουν βελτιώσεις στον κώδικα, αλλά την συγκεκριμένη στιγμή ο αλγόριθμος λειτουργεί επιτυχώς και συγχρονίζει τα ραντεβού του συστήματος με τα συμβάντα που έχει περάσει ο χρήστης στο Google Calendar με επιτυχία. + +\lstinputlisting{snippets/google_sync_algorithm.php} + +Η μέθοδος αυτή καλείται κάθε φορά που πρέπει να τρέξει ο αλγόριθμος συγχρονισμού για έναν πάροχο υπηρεσιών. Στο πρώτο μέρος του κώδικα ελέγχεται αν ο χρήστης έχει τα δικαιώματα να τρέξει αυτήν την μέθοδο και αν έχει δοθεί το αναγνωριστικό της εγγραφής του πάροχου. Έπειτα φορτώνονται τα απαραίτητα models και γίνεται η λήψη των πληροφοριών του πάροχου από την βάση (γραμμές 17 - 31). + +Για να συνεχιστεί η διαδικασία θα πρέπει να ελεγχθεί αν ο πάροχος έχει ενεργό τον συγχρονισμό με το Google Calendar. Αυτό είναι απαραίτητο διότι για να χρησιμοποιηθεί το Google Calendar API + +%% ================================================== +%% ΔΙΑΓΡΑΜΜΑΤΑ ΚΩΔΙΚΑ +%% ================================================== \section{Διαγράμματα Κώδικα} Σε αυτήν την ενότητα θα παρατεθούν κάποια διαγράμματα κώδικα τα οποία θα βοηθήσουν τον αναγνώστη στην κατανόηση της λειτουργίας του συστήματος και στον τρόπο με τον οποίο διεκπεραιώνονται οι εργασίες που απαιτούνται στην εκάστοτε περίπτωση χρήσης. @@ -133,15 +160,3 @@ public function find_record_id($admin) { \caption{Σε αυτό το διάγραμμα κλάσεων φαίνεται οι κλάσεις που συμμετέχουν στον JavaScript κώδικα των κεντρικών ρυθμίσεων της εφαρμογής. Οι κάθε μια κλάση αντιπροσωπεύει την λειτουργία μιας κατηγορίας ρυθμίσεων και μαζί χρησιμοποιούνται για την σωστή λειτουργία της σελίδας.} \label{cd-backend-settings} \end{figure} - -%% ================================================== -%% ΑΝΑΛΥΣΗ ΒΑΣΙΚΩΝ ΑΛΓΟΡΙΘΜΩΝ -%% ================================================== -\section{Ανάλυση Βασικών Αλγορίθμων} -Σε αυτήν την ενότητα θα γίνει ανάλυση κάποιων βασικών αλγορίθμων που αποτελούν χρήσιμα τμήματα στην λειτουργία του συστήματος. Θα γίνει περιγραφή της λειτουργίας τους και επεξήγηση της δομής καθώς και των αποφάσεων που έχουν παρθεί κατά την σχεδίαση και υλοποίηση τους. - -\subsection{Συχρονισμός Google Calendar} -Η διαδικασία του πλήρη συγχρονισμού ραντεβού με το Google Calendar απότελεί ένας από τους κυριότερους αλγορίθμους του συστήματος. Η ανάγκη για έναν ολοκληρωμένο αλγόριθμο και η πολυπλοκότητα της διαδικασίας συγχρονισμού δεδομένων κατέστησαν την υλοποίηση αυτού του τμήματος κώδικα πολύ σημαντικό κατά την διάρκεια της ανάπτυξης της εφαρμογής. Μπορεί μελλοντικά να παρατηρηθούν ελλείψεις ή να υπάρξουν βελτιώσεις στον κώδικα, αλλά την συγκεκριμένη στιγμή ο αλγόριθμος συγχρονισμού ραντεβού λειτουργεί επιτυχώς και συγχρονίζει τα ραντεβού του Easy!Appointments με τα συμβάντα που έχει περάσει ο χρήστης στο Google Calendar. - -Προϋπόθεση για την χρήση της λειτουργίας συγχρονισμού της εφαρμογής είναι να έχει δημιουργηθεί ένα API Key στην υπηρεσία Google API Console. - diff --git a/doc/thesis/snippets/google_sync_algorithm.php b/doc/thesis/snippets/google_sync_algorithm.php new file mode 100644 index 00000000..2deba89d --- /dev/null +++ b/doc/thesis/snippets/google_sync_algorithm.php @@ -0,0 +1,161 @@ +load->library('session'); + if ($this->session->userdata('user_id') == FALSE) return; + + if ($provider_id === NULL) { + throw new Exception('Provider id not specified.'); + } + + $this->load->model('appointments_model'); + $this->load->model('providers_model'); + $this->load->model('services_model'); + $this->load->model('customers_model'); + $this->load->model('settings_model'); + + $provider = $this->providers_model->get_row($provider_id); + + // Check whether the selected provider has google sync enabled. + $google_sync = $this->providers_model + ->get_setting('google_sync', $provider['id']); + if (!$google_sync) { + throw new Exception('The selected provider has not the ' + . 'google synchronization setting enabled.'); + } + + $google_token = json_decode($this->providers_model + ->get_setting('google_token', $provider['id'])); + $this->load->library('google_sync'); + $this->google_sync->refresh_token($google_token->refresh_token); + + // Fetch provider's appointments that belong to the + // sync time period. + $sync_past_days = $this->providers_model + ->get_setting('sync_past_days', $provider['id']); + $sync_future_days = $this->providers_model + ->get_setting('sync_future_days', $provider['id']); + $start = strtotime('-' . $sync_past_days . ' days', + strtotime(date('Y-m-d'))); + $end = strtotime('+' . $sync_future_days . ' days', + strtotime(date('Y-m-d'))); + + $where_clause = array( + 'start_datetime >=' => date('Y-m-d H:i:s', $start), + 'end_datetime <=' => date('Y-m-d H:i:s', $end), + 'id_users_provider' => $provider['id'], + 'is_unavailable' => FALSE + ); + + $appointments = $this->appointments_model + ->get_batch($where_clause); + + $company_settings = array( + 'company_name' => + $this->settings_model->get_setting('company_name'), + 'company_link' => + $this->settings_model->get_setting('company_link'), + 'company_email' => + $this->settings_model->get_setting('company_email') + ); + + // Sync each appointment with Google Calendar by following + // the project's sync protocol (see documentation). + foreach($appointments as $appointment) { + $service = $this->services_model + ->get_row($appointment['id_services']); + $customer = $this->customers_model + ->get_row($appointment['id_users_customer']); + + // If current appointment not synced yet, add to gcal. + if ($appointment['id_google_calendar'] == NULL) { + $google_event = $this->google_sync + ->add_appointment($appointment, $provider, $service, + $customer, $company_settings); + $appointment['id_google_calendar'] = $google_event->id; + $this->appointments_model->add($appointment); // Save gcal id + } else { + // Appointment is synced with google calendar. + try { + $google_event = $this->google_sync + ->get_event($appointment['id_google_calendar']); + + // If gcal event is different from e!a appointment then + // update Easy!Appointments record. + $is_different = FALSE; + $appt_start = strtotime($appointment['start_datetime']); + $appt_end = strtotime($appointment['end_datetime']); + $event_start = + strtotime($google_event->getStart()->getDateTime()); + $event_end = + strtotime($google_event->getEnd()->getDateTime()); + + if ($appt_start != $event_start + || $appt_end != $event_end) { + $is_different = TRUE; + } + + if ($is_different) { + $appointment['start_datetime'] = + date('Y-m-d H:i:s', $event_start); + $appointment['end_datetime'] = + date('Y-m-d H:i:s', $event_end); + $this->appointments_model->add($appointment); + } + + } catch(Exception $exc) { + // Appointment not found on gcal, delete from e!a. + $this->appointments_model->delete($appointment['id']); + $appointment['id_google_calendar'] = NULL; + } + } + } + + // :: ADD GCAL EVENTS THAT ARE NOT PRESENT ON E!A + $events = $this->google_sync->get_sync_events($start, $end); + + foreach($events->getItems() as $event) { + $results = $this->appointments_model->get_batch( + array('id_google_calendar' => $event->getId())); + if (count($results) == 0) { + // Record doesn't exist in E!A, so add the event now. + $appointment = array( + 'start_datetime' => date('Y-m-d H:i:s', + strtotime($event->start->getDateTime())), + 'end_datetime' => date('Y-m-d H:i:s', + strtotime($event->end->getDateTime())), + 'is_unavailable' => TRUE, + 'notes' => $event->getSummary() + . ' ' . $event->getDescription(), + 'id_users_provider' => $provider_id, + 'id_google_calendar' => $event->getId(), + 'id_users_customer' => NULL, + 'id_services' => NULL, + ); + + $this->appointments_model->add($appointment); + } + } + + echo json_encode(AJAX_SUCCESS); + + } catch(Exception $exc) { + echo json_encode(array( + 'exceptions' => array($exc) + )); + } +} \ No newline at end of file diff --git a/doc/thesis/thesis.pdf b/doc/thesis/thesis.pdf index 06464128..20a323b0 100644 Binary files a/doc/thesis/thesis.pdf and b/doc/thesis/thesis.pdf differ