Projekt Flotter Flitzer

Aus Informatik
Wechseln zu: Navigation, Suche

Problembeschreibung

Flitzer erm orig.jpg

Die Autovermietung „Flotter Flitzer“ ist auf die Vermietung luxuriöser Sportwagen spezialisiert. Dieser Wagentyp bildet das Hauptangebot, daneben können aber auch mehrere Mittelklassewa-gen nachgefragter Modelle verschiedener Hersteller gemietet werden.

Als Daten der Kundschaft werden KundenNr, Name, Anschrift, Telefon und die Personalaus-weisnummer erfasst. Für die PKWs werden Kennzeichen, der Kilometerstand, Preis pro gefahre-ner Kilometer, Mietpauschale, Hersteller mit Namen, Anschrift, Telefon des Herstellers und Kontaktperson beim Hersteller, Modellname, Leistung, Hubraum, Farbe und das Datum der Erstzulassung erfasst. Auf weitere Ausstattungsdetails wird in der Aufgabe verzichtet.

Bei der Ausleihe erfolgen gegebenenfalls die Kundenregistrierung und die Pkw-Zuteilung mit Eingabe des aktuellen Kilometerstands und des Ausleihdatums. Bei der Rückgabe des Autos werden das Rückgabedatum und wieder der aktuelle Kilometerstand erfasst. Abgerechnet wird nach gefahrenen Kilometern.

Dazu kommt eine Mietpauschale, die in jedem Fall zu zahlen ist und zwar unabhängig von der Nutzungsdauer und den gefahrenen Kilometern. Nunmehr soll die Verwaltung auf EDV umge-stellt werden. Vorgesehen ist eine relationale Datenbank, mit der zunächst die Vermietung und die Verwaltung des Fuhrparks abgewickelt werden können. Dazu entwirft ein Mitarbeiter das nebenstehende ER-Diagramm.

MySQL-Datenbank

Entity-Relationship-Modell

Flitzer erm vollstaendig.jpg

Geschäftsregeln:

  • Ein Kunde kann beliebig viele Autos leihen, muss aber nicht.
  • Ein PKW kann höchstens ein mal geliehen werden, muss aber nicht.
  • Ein PKW gehört zu genau einem Modell.
  • Zu einem Modell können beliebig viele PKWs gehören, aber mindestens einer.
  • Ein Hersteller produziert beliebig viele Modelle, aber mindestens eins.
  • Ein Modell wird von genau einem Hersteller produziert.

Relationen-Modell

  • kunde(knr, vorname, nachname, anschrift, telefon, personr)
  • pkw(kennzeichen, erstzulassung, tachostand, farbe, ausleihdatum, mnr, knr)
  • modell(mnr, modellname, hubraum, leistung, kmpreis, pauschale, hnr)
  • hersteller(hnr, name, anschrift, telefon, kontaktperson)

Datenbankstruktur

CREATE TABLE kunde (
	knr integer auto_increment,
	vorname varchar(10) not null,
	nachname varchar(10) not null,
	anschrift varchar(50) not null,
	telefon varchar(15) not null,
	personr integer not null,
	PRIMARY KEY (knr)
)ENGINE=INNODB AUTO_INCREMENT=1;

CREATE TABLE hersteller (
	hnr integer auto_increment,
	name varchar(20) not null,
	anschrift varchar(50) not null,
	telefon varchar(15) not null,
	kontaktperson varchar(20) not null,
	PRIMARY KEY (hnr)
)ENGINE=INNODB AUTO_INCREMENT=1;

CREATE TABLE modell (
	mnr integer auto_increment,
	modellname varchar(20) not null,
	hubraum integer not null,
	leistung integer not null,
	kmpreis float not null,
	pauschale float not null,
	hnr integer,
	PRIMARY KEY (mnr),
	FOREIGN KEY (hnr) REFERENCES hersteller(hnr)
		ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE=INNODB AUTO_INCREMENT=1;

CREATE TABLE pkw (
	kennzeichen varchar(9),
	erstzulassung date not null,
	tachostand integer not null,
	farbe varchar(6) not null,
	ausleihdatum date,
	mnr integer,
	knr integer,
	PRIMARY KEY (kennzeichen),
	FOREIGN KEY (mnr) REFERENCES modell(mnr)
		ON DELETE RESTRICT ON UPDATE CASCADE,
	FOREIGN KEY (knr) REFERENCES kunde(knr)
		ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE=INNODB;

Datenbankdatei

Datei:Flitzer datenbank.zip

(Die Datenbankdatei wurde mit phpMyAdmin exportiert und enthält einige Datensätze.)

Umsetzung

Layout

genereller Aufbau

Screenshot Markierung der einzelnen Komponenten

Ganz oben auf der Hauptansicht befinden sich zur Auswahl der verschiedenen Datenbanktabellen "Kunden", "PKWs" und "Hersteller" einzelne Tabs. Darunter befindet sich die Datenanzeige, die eine Tabelle der einzelnen Datensätze mit den wichtigsten Informationen und den Aktionsmöglichkeiten löschen und Details enthält. Unter dieser Tabelle ist die Fußleiste platziert, die einen Link zur Erstellung neuer Datensätze enthält. Auf der rechten Seite der Hauptansicht ist ein Filter, der eine Einschränkung der Datenanzeige auf relevante Daten ermöglicht.

Die Dialoge zur Erstellung neuer Datensätze bestehen lediglich aus Formularen, während die Detailanzeigen unterteilt sind. Bei den Kunden werden neben den einzelnen Information alle ausgeliehenen Fahrzeuge in einer Tabelle angezeigt. Die PKW-Details enthalten unterteilt sowohl Informationen des einzelnen PKW als auch des Modells. Bei den Details der Hersteller werden hingegen nur die Informationen angezeigt, die in der Relation "Hersteller" vorhanden sind. In den Detailanzeigen befindet sich jeweils ein Link, der die Bearbeitung der angezeigten Daten ermöglicht.

Navigationsstruktur

Navigationsstruktur der Website

Der Ausgangspunkt ist die Hauptansicht, in der zwischen den Kategorien gewählt werden kann. Von dort aus können Fenster zum Anlegen neuer Datensätze, sowie die Detailansicht geöffnet werden. Aus der Detailansicht der Kunden bzw. der PKWs kann man dann neue PKWs ausleihen und geliehene PKWs zurückgeben. Hierbei ist zu beachten, dass der Ausleihvorgang in zwei Schritten erfolgt, wobei der erste in zwei verschiedenen Varianten existiert: Einmal zur Wahl des betreffenden Kunden und einmal zur Wahl des betreffenden PKWs.

Tabellen zur Strukturierung

Screenshot mit sichtbarer Tabelle

Das Layout basiert fast vollständig auf Tabellen. Bilder und Inhalte befinden sich in den Zellen unsichtbarer Tabellen, sodass die Positionen genau bestimmt werden können, ohne dass die Tabellen bemerkt würden. Die Tabelle im Hauptfenster wurde auf dem rechten Bild sichtbar gemacht. Der schwarze Rahmen und die Tabs bestehen ausschließlich aus PNG-Bildern. Diese haben den Vorteil, dass sie teilweise durchsichtbar sind, was wiederum ermöglicht, dass die Hintergrundfarbe in der style.css einfach geändert werden kann, ohne die Farbe auf den Bildern ändern zu müssen.

scrollbarer Bereich

Im Hauptfenster befinden sich die Tabellen von Kunde, Hersteller und PKWs in scrollbaren Bereichen, die dafür sorgen, dass man die Tabellen vollständig anzeigen kann, auch wenn sie eigentlich zu viele Zielen für einen Bereich mit fester größe haben. Dies ist mit einem CSS-formatierten DIV-Bereich realisiert.

Und zwar muss mit der CSS Eigenschaft height eine Höhe des Bereichs festgelegt werden und dann kann mit der Eigenschaft overflow angegeben werden, was passieren soll, wenn der Inhalt diese Größe überschreitet. Mit overflow: auto werden die Scrolleisten nur eingeblendet, wenn die Höhe überschritten wird, mit overflow: scroll werden sie immer eingeblendet.

Soll nur vertikal gescrollt werden, muss man die CSS-Eigenschaft overflow-y mutzen. Allerdings wird diese erst von Opera 9.5 unterstützt.

JavaScript

Formularüberprüfung

Zum einen werden schon mittels HTML die Längen der Formulareingaben begrenzt, zum anderen werden die Eingaben durch JavaScript auf gültigkeit überprüft. Dazu wird in das Tag des Formulars folgender Listener hinzugefügt:

onsubmit="return checkform('filter_form')"

An diese Funktion wird der Name des Formulars übergeben. Wenn die Funktion true zurückgibt, wird das Formular abgesendet, andernfalls nicht. Die Funktion checkform sieht dann folgendermaßen aus:

function checkform(formname) {
	var strFehler = ;
	var testvar = ;

	testvar = document.forms[formname].knr.value; // Inhalt des Formularfelds in die Variable 'testvar' kopieren
	if (checkinteger(testvar) == false) {         // Feld prüfen
		strFehler = strFehler + 'Die Kundennummer ist ungültig.\n';
	}

... (Für jedes Feld wird eine solche Prüfung durchgeführt.)

	if (strFehler == ) {
		return(true);
	} else {
		alert(strFehler);                     // Meldung mit Fehlerbeschreibung anzeigen
		return(false);
	}
}

Immer wenn ein Fehler auftritt, wird die entsprechende Meldung in die Variable strFehler geschrieben. Sollte diese am Ende gefüllt sein, wird die Fehlermeldung ausgegeben und die Funktion liefert false zurück, andernfalls true.

Die konkrete Überprüfung findet dann mit der Funktion checkinteger(testvar) statt, welche so aufgebaut ist:

function checkinteger(input) {
	if (input.length == 0 ) {
		return(true);
	} else {
		var muster = /^[0-9]*$/;              // regulärer Ausdruck des gewünschten Inhalts
		var Ergebnis = muster.test(input);    // Überprüfung anhand des regulären Ausdrucks
		return(Ergebnis);
	}
}

Die Funktion liefert zunächst für ein leeres Feld true zurück (Feld soll auch leer bleiben dürfen). Wenn dies nicht der Fall ist, wird ein regulärer Ausdruck des erlaubten Inhalts angelegt, anhand dessen dann der übergebene String überprüft wird. Dieser reguläre Ausdruck testet auf ganze Zahlen. Natürlich gibt es hier für andere Datentypen andere Ausdrücke, beispielsweise /^[abcdefABCDEF0-9]*$/ für hexadezimale Farbangaben oder /^[A-Z]{1,3}\s[A-Z]{1,2}\s[1-9][0-9]{0,3}$/ für KFZ-Kennzeichen.

POST-Daten mit JavaScript übertragen

Wenn ein Datensatz gelöscht werden soll, wird auf ein Link geklickt, der eine Variable mit dem Primärschlüssel des zu löschenden Datensatzes an den Server überträgt. Mit GET-Variablen ist dies kein Problem, allerdings etwas unsicher, wenn ein solcher Löschbefehl in der Adresse gespeichert ist. Deshalb gibt es eine saubere Möglichkeit, den Löschbefehl per POST zu schicken. Dazu wird im HTML-Code ein unsichtbares Formular angelegt:

<div style="display: none">                        // versteckt das Formular
 	<form method="post" action="index.php" id="hiddenForm"></form>
</div>

Dann wird vom "Lösch-Link" eine JavaScript-Funktion aufgerufen:

<a href="javascript:kunde_loeschen('<?php echo $row['knr'] ?>')">löschen</a>

Der Funktion wird die Kundennummer des zu löschenden Kunden übergeben. Die entsprechende Kundennummer wird durch PHP in den HTML-Code geschrieben. Die JavaScript-Funktion sieht so aus:

function kunde_loeschen(knr) {
	if (confirm('Wollen Sie diesen Kunden wirklich löschen?')) { // Löschen bestätigen
		var input1 = document.createElement('INPUT');        // neues Feld erzeugen
		input1.type = 'hidden';
		input1.value = knr;                                  // Wert des Feldes
		input1.name = 'del';                                 // Name des Feldes
		input1.id = 'del';
		document.getElementById('hiddenForm').appendChild(input1);
                                                                     // Feld zum versteckten
                                                                        Formular hinzufügen
		document.getElementById('hiddenForm').submit();      // Formular abschicken
	}
}

JavaScript kann ein neues Formularfeld mit der entsprechenden Kundennummer als Wert anlegen. Dieses wird dann zum versteckten Formular hinzugefügt und abgeschickt.

Datum in Kalender auswählen

Da bei diesem Projekt einige Male ein Datum eingegeben werden muss, habe ich einen auf JavaScript basierten Kalender von goweb.de eingebunden. Die verlinkte Seite zeigt wie dies geschehen muss. Zusatzlich habe ich den Kalender ein klein wenig abgeändert.

Wenn man in der cal.js die Zeile 276 von

anzeige: function(monat, jahr, obj, pdays, tdays, layout) {

in

anzeige: function(monat, jahr, obj, pdays, tdays, layout, topdistance) {

und die Zeile 306 von

c.style.top =  (yFromTop+Kalender.lastMouseY) + "px";

in

c.style.top =  (yFromTop+Kalender.lastMouseY-topdistance) + "px";

umändert, kann beim Aufrufen des Kalenders am Ende noch ein zusätzlicher Parameter übergeben werden, der den Kalender um eine bestimmte Anzahl Pixel nach oben verschiebt. Dies ist praktisch, wenn der Kalender sonst nach unten über das Browserfenster hinaus aufgehen würde.

PHP

Datenmanipulation

Im Folgenden wird an der Änderung der Kundeninformationen bespielhaft gezeigt, wie eine Datenmanipulation mittels PHP und SQL erfolgen kann.

Zunächst müssen dazu alle relevanten Informationen aus dem entsprechenden Formular eingelesen werden. Diese werden, wenn vorhanden, in ein Array gespeichert. Wenn eine Information nicht vorhanden ist, wird die Variable $update auf false gesetzt und eine Aktualisierung der Daten findet nicht statt.

$update = true;

if (is_null($_POST['nachname'])) {
	$update = false;
} else {
	$info['nachname'] = $_POST['nachname'];
}
if (is_null($_POST['vorname'])) {
	$update = false;
} else {
	$info['vorname'] = $_POST['vorname'];
}
if (is_null($_POST['anschrift'])) {
	$update = false;
} else {
	$info['anschrift'] = $_POST['anschrift'];
}
if (is_null($_POST['telefon'])) {
	$update = false;
} else {
	$info['telefon'] = $_POST['telefon'];
}
if (is_null($_POST['personr'])) {
	$update = false;
} else {
	$info['personr'] = $_POST['personr'];
}
$info['knr'] = $knr;  // Die Kundennummer wurde vorher bereits über eine GET-Variable übermittelt

Wenn die Variable $update true ist, wird die Funktion update_kunde aufgerufen und ihr das Array mit den Informationen übergeben. Diese Funktion gibt true zurück, falls der Vorgang erfolgreich war, andernfalls false. Dies kann später zur Anzeige einer Rückmeldung genutzt werden.

if ($update) {
	$erfolgreich = update_kunde($info);
}

In einer seperaten, nur zum Anlegen und Ändern von Datensätzen bestimmtem PHP-Datei befindet sich nun die Funktion update_kunde. Diese setzt zunächst einen String mit dem UPDATE-Befehl der SQL-Datenbank zusammen. Dazu nutzt sie die Informationen des übergebenen Arrays. Danach wird der Befehl ausgeführt und das Ergebnis dieses Befehls zurückgegeben.

function update_kunde($info) {
	$query ="UPDATE kunde
		SET nachname = '".$info['nachname']."' , vorname = '".$info['vorname']."' ,
			anschrift = '".$info['anschrift']."' , telefon = '".$info['telefon']."' ,
			personr = ".$info['personr']." 
		WHERE knr = ".$info['knr'];
	return mysql_query($query);
}

fertige Website

Datei:Flitzer website.zip

Hinweise:

  • In Opera 9 lassen sich übergroße Tabellen nicht richtig darstellen.
  • Als Mindestauflösung wird 1024x768 empfohlen.
  • JavaScript muss auf jeden Fall aktiviert sein.