INTRODUCTION |
De nos jours, les réservations de places de spectacle sont effectuées presque exclusivement au moyen de systèmes de réservation en ligne qui utilisent des bases de données pour gérer les données. Des spécialistes en bases de données pourvus de très grandes compétences en programmation sont responsables du développement de ce genre de systèmes.
|
SYSTÈME DE RÉSERVATION, ÉTAPE 1 : INTERFACE GRAPHIQUE |
Il faut prévoir une interface graphique attractive pour présenter le système à l’utilisateur. Une telle interface peut être réalisée au travers d’une application Desktop classique ou d’une application Web. L’interface d’un système de réservation affiche généralement la disposition des sièges dans la salle de spectacle ou dans l’avion pour permettre à l’utilisateur de réserver son siège de manière fondée, sur la base d’une bonne représentation spatiale. La disponibilité des sièges est rendue immédiatement apparente par un code couleur : rouge pour les sièges réservés et vert pour ceux qui sont encore libres. L’utilisateur peut se contenter de cliquer sur un siège vide pour en demander la réservation, de sorte qu’il va changer de couleur. Cette sélection n’est à ce stade pas encore communiquée à la base de données puisque l’utilisateur va généralement réserver plusieurs chaises ou changer d’avis au cours de sa réservation. Le processus de réservation définitive n’est initié que lorsque l’utilisateur confirme sa réservation en cliquant sur un bouton approprié. La bibliothèque de jeux JGameGrid est idéale pour implémenter cette interface graphique puisque les sièges sont généralement arrangés selon une structure de grille. L’identifiant de sprite (0, 1, 2) peut être utilisé pour permettre de changer l’état de disponibilité des sièges (libre, en cours de réservation, réservé).
Le programme suivant constitue déjà une interface graphique pleinement fonctionnelle. Il lui manque cependant encore la connexion à la base de données [plus...
Au cas où certains éléments de ce programme devaient vous échapper, from gamegrid import * def toLoc(seat): i = ((seat - 1) % 6) + 1 k = ((seat - 1) // 6) + 2 return Location(i, k) def toSeatNb(loc): if loc.x < 1 or loc.x > 6 or loc.y < 2 or loc.y > 6: return None i = loc.x - 1 k = loc.y - 2 seatNb = k * 6 + i + 1 return seatNb class MyButton(GGButton, GGButtonListener): def __init__(self, imagePath): GGButton.__init__(self, imagePath) self.addButtonListener(self) def buttonClicked(self, button): if button == confirmBtn: confirm() if button == renewBtn: renew() def buttonPressed(self, button): pass def buttonReleased(self, button): pass def renew(): setStatusText("View refreshed") def confirm(): for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: seats[seatNb - 1].show(2) refresh() setStatusText("Reservation successful") def pressCallback(e): loc = toLocation(e.getX(), e.getY()) seatNb = toSeatNb(loc) if seatNb == None: return seatActor = seats[seatNb - 1] if seatActor.getIdVisible() == 0: # free seatActor.show(1) # option refresh() elif seatActor.getIdVisible() == 1: # option seatActor.show(0) # free refresh() makeGameGrid(8, 8, 40, None, "sprites/stage.gif", False, mousePressed = pressCallback) addStatusBar(30) setTitle("Seat Reservation") setStatusText("Please select free seats and press 'Confirm'") confirmBtn = MyButton("sprites/btn_confirm.gif") renewBtn = MyButton("sprites/btn_renew.gif") addActor(confirmBtn, Location(1, 7)) addActor(renewBtn, Location(6, 7)) seats = [] for seatNb in range(1, 31): seatLoc = toLoc(seatNb) seatActor = Actor("sprites/seat.gif", 3) seats.append(seatActor) addActor(seatActor, seatLoc) addActor(TextActor(str(seatNb)), seatLoc) show()
|
MEMENTO |
Le passage d’un numéro de siège en sa position dans la grille (Location) et vis-versa est réalisé au sein de deux fonctions de transformation. Le nom de telles fonctions de conversion est généralement préfixé de to (vers en anglais). |
SYSTÈME DE RÉSERVATION, ÉTAPE 2 : CONNEXION À LA BASE DE DONNÉES |
Les bases de données en ligne sont des systèmes multi-utilisateurs. Du fait que de nombreux clients manipulent les données en même temps, de nombreux problèmes de conflits d’accès peuvent survenir dans certaines situations. Les problèmes de ce type sont par nature sporadiques et donc très difficilement gérables. Le scénario suivant décrit un cas typique de conflit d’accès pour notre système de réservation :
Deux clients A et B effectuent une réservation en même temps. Au début, les deux clients A et B vont interroger la base de données pratiquement en même temps pour connaître les sièges encore libres. Les deux reçoivent donc exactement la même information et possèdent donc la même vision de la situation (vert = siège libre, rouge = siège réservé).
Remarque : L’exécution du programme suivant présuppose que le serveur de bases de données est démarré et que la table reservation a été créée et remplie avec les données d’initialisation (voir chapitre précédent). from dbapi import * from gamegrid import * serverURL = "derbyserver:localhost" #serverURL = "derbyserver:10.1.1.123" dbname = "casino" username = "admin" password = "solar" tbl = "reservation" def toLoc(seat): i = ((seat - 1) % 6) + 1 k = ((seat - 1) // 6) + 2 return Location(i, k) def toSeatNb(loc): if loc.x < 1 or loc.x > 6 or loc.y < 2 or loc.y > 6: return None i = loc.x - 1 k = loc.y - 2 seatNb = k * 6 + i + 1 return seatNb def pressCallback(e): loc = toLocation(e.getX(), e.getY()) seatNb = toSeatNb(loc) if seatNb == None: return seatActor = seats[seatNb - 1] if seatActor.getIdVisible() == 0: # free seatActor.show(1) # option refresh() elif seatActor.getIdVisible() == 1: # option seatActor.show(0) # free refresh() class MyButton(GGButton, GGButtonListener): def __init__(self, imagePath): GGButton.__init__(self, imagePath) self.addButtonListener(self) def buttonClicked(self, button): if button == confirmBtn: confirm() if button == renewBtn: renew() def buttonPressed(self, button): pass def buttonReleased(self, button): pass def renew(): with connect(serverURL, dbname, username, password) as con: cursor = con.cursor() sql = "SELECT * FROM " + tbl cursor.execute(sql) con.commit() result = cursor.fetchall() for record in result: seatNb = record[0] isBooked = (record[1] != 'N') if isBooked: seats[seatNb - 1].show(2) else: seats[seatNb - 1].show(0) refresh() setStatusText("View refreshed") def confirm(): # check if seats is still available with connect(serverURL, dbname, username, password) as con: cursor = con.cursor() for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: sql = "SELECT * FROM " + tbl + " WHERE seat=" + str(seatNb) cursor.execute(sql) result = cursor.fetchall() for record in result: if record[1] == 'Y': setStatusText("One of the seats are already taken.") return isReserved = False for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: sql = "UPDATE " + tbl + " SET booked='Y' WHERE seat=" + \ str(seatNb) cursor.execute(sql) isReserved = True con.commit() renew() if isReserved: setStatusText("Reservation successful") else: setStatusText("Nothing to do") makeGameGrid(8, 8, 40, None, "sprites/stage.gif", False, mousePressed = pressCallback) addStatusBar(30) setTitle("Seat Reservation - Loading...") confirmBtn = MyButton("sprites/btn_confirm.gif") renewBtn = MyButton("sprites/btn_renew.gif") addActor(confirmBtn, Location(1, 7)) addActor(renewBtn, Location(6, 7)) seats = [] for seatNb in range(1, 31): seatLoc = toLoc(seatNb) seatActor = Actor("sprites/seat.gif", 3) seats.append(seatActor) addActor(seatActor, seatLoc) addActor(TextActor(str(seatNb)), seatLoc) show() renew() setTitle("Seat Reservation - Ready") setStatusText("Select free seats and press 'Confirm'") while not isDisposed(): delay(100)
|
MEMENTO |
|
EXERCICES |
|