![]() |
[PHP] Klassenstruktur für Adressdatenbank
Hallo,
ich habe ein private MySQL Adressdatenbank auf meinem Server. Bisher ist der PHP-Code ziemlich unstrukturiert und prozedural. Das wollte ich jetzt ändern und das ganze objektorientiert neu Programmieren. Ich finde aber noch keine mir zusagende Klassenstruktur. Was ich bisher habe: - eine Klasse für einen einzelnen Kontakt - eine Containerklasse für mehrere Kontakte, die eventuell von einem Query zurückgegeben werden (Wird eventuell durch ein einfaches Array ersetzt) - .... Ja und jetzt weiß ich nicht so ganz weiter. Ich bräuchte noch Klassen für verschiedene Views: Einzelansicht, mehrere Datensätze (mit der Möglichkeit seitenweise zu blättern), eine Klasse für das Anlegen und Löschen eines neuen Kontaktes, ... Und ich überlege, ob ich der Klasse für einen einzelnen Kontakt Methoden spendiere zum Speichern und Ändern oder ob ich das in die Klasse zum Anlegen und Löschen eines Kontaktes packe. Gibt es für das Problem eine Standardlösung? Ich will aber keine fertigen Frameworks. Es ist für mich auch eien Fingerübung zum Lernen von PHP. |
AW: [PHP] Klassenstruktur für Adressdatenbank
Grundsätzlich solltest du ein Framework verwenden.
Mit PHP kann man unheimlich leicht Webseiten programmieren, welche viele Sicherheitslücken enthalten. Ein Framework hilft etwas, dass zu vermeiden. Die gängigen sind Zend_Framework oder etwas mehr high level das Flow3. Flow3 ist derzeit das modernste was es gibt. Die Leute haben sich viele Gedanken gemacht. Ziel war es "secure by default" zu sein. Wenn du "nur" eine kleine Verwaltung willst, könntest du auch zum CMS PimCore greifen. Wenn du es doch per Hand machen willst, dann verwenden zumindest eine Template-Engine z.B. Smarty und einen fertigen DB-Layer. |
AW: [PHP] Klassenstruktur für Adressdatenbank
Eine Klasse zum Anlegen und Löschen von Kontakten? Ne!
Eigentlich suchst du einen ORM, wie CakePHP. Das ist ziemlich genau das was du brauchst. Wenn du dich mit der API solcher ORM mal auseinander setzen würdest, dann wäre dir sicher auch viel klarer, wie die Klassen zu strukturieren sind. Ich finde eigentlich, dass du hier viel zu viele unnötige Klassen benutzt. Bei mir gäbe es eine einzige Klasse Kontakt. Diese macht alles was man braucht. Sie besitzt statische Methoden zum Anlegen eines neuen Kontakts (die dann den Kontakt zurückgeben), Methoden zum löschen und weitere statische Methoden zum Filtern. Contact::get() liefert alle Kontakte, Contact::findByPhone(...) alle mit bestimmter Nummer. In richtigen ORM wird ein Select erst ausgeführt, wenn man die Daten tatsächlich braucht. Damit benutzt man dann Konstrukte wie:
Code:
Natürlich kann man hier viel mehr Klassen erstellen, das macht man auch insbesondere dann, wenn weitere solche Tabellen gebraucht werden. Der Contact sollte von (abstract) Table erben, die die wichtigsten Operationen wie get, insert, delete usw. bereitstellt. Die Contact-Klasse selbst definiert dann lediglich ihr Layout im Konstruktor ($this->add_column) und bietet weiterführende Methoden an. So benutze ich es jedenfalls seit Jahren.
$myList = Contact::byCountry('de')->limit(0, 20);
Das ganze Framework dafür kann sehr sehr viel Arbeit kosten. Ich habe sowas allerdings auch schon mal selbst erstellt und es hat riesen Spaß gemacht. Dennoch ist man mit einem Framework, auch wenn ich mir bei dem Begriff in dem Fall nicht sicher bin, besser beraten. Gerade weil man dadurch mehr lernt als durch falsches Probieren. Überlege dir, ob CakePHP dir zusagt. Es reicht ja, wenn du den ORM daraus verwendest. Das Zend Framework ist auch genial, aber sehr umfangreich. Auch hier musst du nicht alles verwenden. Du gehst den richtigen Weg und lernen wie es geht ist definitiv wichtig. Aber es ist schlauer sich anzuschauen wie andere Frameworks funktionieren, oder zumindest welche API sie anbieten. Sich das abzuschauen ist nicht verboten und bei Bedarf dann doch selbst zu machen, wenn man will, bringt mehr Vorteile. Schau doch wenigstens ein paar Tutorials zu ORM in PHP, damit kann man schon einen Überblick bekommen wie es dort aufgebaut ist. :-) Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
@generic: Wie ich schon sagte, ich will lernen. Und wenn ich nur fertige Framesworks verwende, bringt mir das nichts. Ich will Fehler machen, denn aus Fehlern lernt man. Und es ist auch nicht sinerheitsrelevant, weil es für mich ist und da eh kein anderer mit arbeitet. Und Mit CakePHPO habe ich schon sehr intensiv gearbeitet.
@Valle: Die Idee mit der einen Klasse hat was. Ich denke, das werde ich weiter verfolgen. |
AW: [PHP] Klassenstruktur für Adressdatenbank
Zitat:
Ausgegangen bin ich u.a. ![]() Wenn Du die Möglichkeit hast, solltest Du Dir auch mal MongoDB ansehen, ideal für Adressen usw. |
AW: [PHP] Klassenstruktur für Adressdatenbank
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Klingt gut. auch wenn ich es selber bastele, werde ich mir das angucken.
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Zitat:
Ich hoffe es macht dir so viel Spaß wie mir, denn ich musste mich echt zurückhalten nicht schon wieder sowas anzufangen. :) Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Könnte ich damit glücklich werden:
Code:
<?php
class DB_Exception extends Exception {} class Contact extends DB_Exception{ private $connection; private $resultset; public $id = array(); public $name = array(); public $vorname = array(); function __construct() { include_once("config.php"); $this->connection = mysql_connect($dbserver, $user, $password); if ($this->connection == false) { die(mysql_error()); } $db = mysql_select_db("usr_l3s11195_1"); if ($db == false) { die(mysql_error()); } } function __destruct() { mysql_free_result($this->resultset); mysql_close($this->connection); } public function getByName() { $query = "SELECT a.*, k.name as k_name FROM adressen_data a LEFT OUTER JOIN adressen_kat k on k.id = a.kategorie_id WHERE a.name LIKE '%".$this->name[0]."%' ORDER BY k.id, a.name, a.vorname, a.gesch_firma"; $this->resultset = mysql_query($query); if (!$this->resultset) { throw new DB_Exception(@mysql_error()); } $this->clearFields(); $this->fillFields(); } public function getBySurname() { $query = "SELECT a.*, k.name as k_name FROM adressen_data a LEFT OUTER JOIN adressen_kat k on k.id = a.kategorie_id WHERE a.vorname LIKE '%".$this->vorname[0]."%' ORDER BY k.id, a.name, a.vorname, a.gesch_firma"; $this->resultset = mysql_query($query); if (!$this->resultset) { throw new DB_Exception(@mysql_error()); } $this->clearFields(); $this->fillFields(); } public function getById() { $query = "SELECT a.*, k.name as k_name FROM adressen_data a LEFT OUTER JOIN adressen_kat k on k.id = a.kategorie_id WHERE a.id = '".$this->id[0]."' ORDER BY k.id, a.name, a.vorname, a.gesch_firma"; $this->resultset = mysql_query($query); if (!$this->resultset) { throw new DB_Exception(@mysql_error()); } $this->clearFields(); $this->fillFields(); } public function save() { } public function edit() { } private function fillFields() { while ($row = mysql_fetch_object($this->resultset)) { $this->id[] = $row->id; $this->name[] = $row->name; $this->vorname[] = $row->vorname; } } private function clearFields() { unset($this->id); unset($this->name); unset($this->vorname); } } ?>
Code:
<?php
include_once("Contact.php"); class View { private $contact; public function getContactByName($filterStr) { try { $this->contact = new Contact(); $this->contact->name[0] = $filterStr; $this->contact->getByName(); $this->htmlOutPut(); } catch(DB_Exception $e) { echo $e->getMessage(); } } public function getContactBySurname($filterStr) { try { $this->contact = new Contact(); $this->contact->vorname[0] = $filterStr; $this->contact->getBySurname(); $this->htmlOutPut(); } catch(DB_Exception $e) { echo $e->getMessage(); } } public function getContactById($Id) { try { $this->contact = new Contact(); $this->contact->id[0] = $Id; $this->contact->getById(); $this->htmlOutPut(); } catch(DB_Exception $e) { echo $e->getMessage(); } } private function htmlOutPut() { for($i=0; $i < count($this->contact->id); $i++) { if (count($this->contact->id) > 1) { echo "ID: ".$this->makeLink("index.php?action=show&id=".$this->contact->id[$i], $this->contact->id[$i])."<br>\n"; echo "Name: ".$this->contact->name[$i]."<br>\n"; echo "Vorame: ".$this->contact->vorname[$i]."<br>\n"; echo "<br>\n"; } else { echo "Name: ".$this->contact->name[$i]."<br>\n"; echo "Vorame: ".$this->contact->vorname[$i]."<br>\n"; echo "<br>\n"; echo $this->makeLink("index.php", "Bearbeiten")." | ".$this->makeLink("index.php", "Löschen")."\n"; } } unset($contact); } private function makeLink($href, $caption) { return "<a href=\"".$href."\">".$caption."</a>"; } } ?>
Code:
Es kommen noch ein paar Suchabfragen dazu und die Datenbank hat so um die 20 Felder.
<html>
<head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> </head> <body> <form action="index.php" method="GET"> <input type="hidden" name="action" value="search"> <select name="field" size="1"> <option value="name">Name</option> <option value="vorname">Vorname</option> </select> <input name="filterStr" type="text"></input> <input type="submit" value="Suchen"></input> </form> <?php include_once("View.php"); $action = $_GET['action']; $id = $_GET['id']; $filterStr = $_GET['filterStr']; $field = $_GET['field']; $view = new View(); switch ($action) { case "search": switch ($field) { case "name": $view->getContactByName($filterStr); break; case "vorname": $view->getContactBySurname($filterStr); break; } break; case "show": $view->getContactById($id); break; default: echo "<a href=\"index.php\"n>Neuer Kontakt</a>\n"; break; } ?> </body> </html> Könnte man auch noch was verbessern oder vereinfachen? Oder könnte ich irgendwo Probleme bekommen? |
AW: [PHP] Klassenstruktur für Adressdatenbank
Du machst das schon ganz gut, denn ich habe schon viel schlimmeres gesehen. Man sieht dass du eine eigene Vorstellung hast, von dem was du tust. Allerdings fehlt hier noch einiges an Praxis-Erfahrung, bzw. do's und don'ts. Für meinen Geschmack ist das auch für ein kleines Privatprojekt noch nicht abstrakt genug. Mach deine Klassen kleiner und dümmer, dafür aber mehr davon. :-) Btw, haben wir jetzt nicht auch [php]?
PHP-Quellcode:
Liebe Grüße,
<?php $answer = 42;
Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Danke für die Tipps und Anregungen. |
AW: [PHP] Klassenstruktur für Adressdatenbank
Zitat:
Zitat:
Man holt sich also die Registry Instanz (siehe Singleton Artikel auf Wikipedia unter PHP), verbindet sich im "Bootloader" mit MySQL und speichert die Connection in diese Registry. Die Db_Table Klasse, von der der Kontakt erben sollte, beschafft sich im Konstruktor diese Verbindung, speichert sie in ein Feld und man arbeitet in der Kontakt-Klasse dann einfach mit $this->db. Zitat:
Zitat:
Zitat:
PHP-Quellcode:
function __get($name) { return $this->data->$name; }
Zitat:
Zitat:
Edit:// Was ich jetzt noch gar nicht bemerkt habe! Du hast alle Methoden nicht-statisch gemacht. Das ist nicht ganz so wie es sein sollte. Stell dir vor, dass die Klasse die Tabelle repräsentiert. Eine Instanz der Klasse repräsentiert eine einzige Zeile dieser Tabelle. Möchtest du also einen speziellen Kontakt, rufst du die statische Methode get($id) der Klasse auf. Diese erzeugt eine Instanz ihrer selbst und gibt sie zurück. Weißt du wie ich das meine? Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
[OT]
Zitat:
[/OT] |
AW: [PHP] Klassenstruktur für Adressdatenbank
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hab hier mal ein kleines UML Diagramm skizziert.
Kursive Klassen sind abstrakt, unterstrichene Methoden sind statisch. Ich garantiere keine Korrektheit oder Vollständigkeit, aber es sollte ungefähr zeigen wie ich mir das vorstelle. :) Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
@Valle: Danke, dass du dir da so deinen Kopf zerbrochen hast. Ich werde es versuchen nach und nach umzusetzen. Ich habe mir mal zwei Sachen rausgepickt als nächsten Milestone:
1. Das mit den Exceptions. 2. Auslagern des Verbindunsgaufbaus. Für beides bräuchte ich aber zum Angucken und nachbauen etwas Beispielcode. |
AW: [PHP] Klassenstruktur für Adressdatenbank
So, meine Exceptionklasse sieht jetzt erst mal so aus:
Code:
Ich habe gelesen, dass man den Konstruktor auf alle Fälle überschreiben und dort den Parent-Konstruktor aufrufen soll. Ich denke mal, so hast du dir das vorgestellt.
<?php
class DBException extends Exception { public function __construct($message, $code = 0) { parent::__construct($message, $code); } } class DBEXception_QueryFailed extends DBException{ public function __construct($message, $code = 0) { parent::__construct($message, $code); } } class DBEXception_EmptyResult extends DBException{ public function __construct($message, $code = 0) { parent::__construct($message, $code); } } ?> |
AW: [PHP] Klassenstruktur für Adressdatenbank
Zitat:
Btw, PHP-Klammer bei PHP-Code bitte weglassen, dann funktioniert das Highlighting. :)
PHP-Quellcode:
Und nochmal btw, du brauchst nach der PHP-Klammer nicht einrücken. Damit sparst du wertvollen Platz nach rechts. Und das Einrücken nach der Klammer ist wirklich sinnlos. (Du rückst in Delphi ja auch nicht nach program oder unit ein. (Oder wie auch immer das da oben heißt^^)
class DBEXception_QueryFailed extends DBException
{} Zitat:
Und hier mal eine einfache und ungetestete Implementation der Registry:
PHP-Quellcode:
Liebe Grüße,
// Registry.php
final class Registry { private static $instance = NULL; private $data = array(); private function __construct() {} private function __clone() {} public static function getInstance() { if (NULL === self::$instance) { self::$instance = new self; } return self::$instance; } public function get($id) { return $this->data[$id]; } public function __get($id) { return $this->get($id); } public function set($id, $value) { $this->data[$id] = $value; } public function __set($id, $value) { return $this->set($id, $value); } // TODO throw exception on missing index // TODO unset, __unset, isset, __isset } // Bootloader.php abstract class Bootloader { private static function connect_mysql() { $registry = Registry::getInstance(); $registry->db = new mysqli('127.0.0.1', '', '', 'mysql'); if (mysqli_connect_error()) { die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); } printf("Connected to %s\n", $registry->db->host_info); } public static function boot() { register_shutdown_function("Bootloader::shutdown"); self::connect_mysql(); } public static function shutdown() { Registry::getInstance()->db->close(); printf("Connection closed.\n"); } } // index.php Bootloader::boot(); // IrgendeinModel.php class Model { public function __construct() { $this->db = Registry::getInstance()->get('db'); echo $this->db->query('SELECT NOW() AS `now`')->fetch_object()->now . "\n"; } } new Model(); Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Super, das habe ich sogar verstanden. Und in der Registry kann man dann ja alles ablegen, was man zwischen speichern will.
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Richtig, dazu ist es da. :)
Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
OK, dann hab eich es verstanden. ;)
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Ein kleines Verständnisproblem hab eich noch.
PHP-Quellcode:
so stelle ich die Verbindung zur Datenbank her.
private static function connect_mysql() {
$connection = mysql_connect($dbserver, $user, $password); if ($connection == false) { die(mysql_error()); } $db = mysql_select_db("usr_l3s11195_1"); if ($db == false) { die(mysql_error()); } $registry = Registry::getInstance(); $registry->db = } Was muss ich jetzt in $register->db speichern, damit ich so $this->db->query('SELECT NOW() AS `now`'); den Query erstellen kann? Und bei $this->resultset = mysql_query($query); schreibe ich dann: $this->resultset = mysql_query(Registry::getInstance()->get('db')); ? |
AW: [PHP] Klassenstruktur für Adressdatenbank
Wenn du PDO schon nicht magst, dann steig doch wenigstens von MySQL auf MySQLi (improved?) um. Das ist quasi das gleiche, aber als objektorientiertes API. Anleitung dazu findest du direkt unter php.net. Schau einfach wie's in meinem Code aussieht, du wirst sehen, dass es fast das gleiche ist. Nur objektoriertiert. :)
(Edit: Nur um das nochmal zu erwähnen. Es ist lediglich ein etwas anders aufgebautes API, MySQL usw. ist nach wie vor das gleiche. Die Umstellung sollte wirklich leicht sein.) Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Bei meinem Webhoster habe ich nur MySQL. Es wäre für mich am einfachsten, das erst mal mit meiner Vorstellung zum Laufen zu bringen. Das ist eh so ein Übungsprojekt, an dem ich immer weiter lernen. aber in kleinen schritten.
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Zitat:
Ansonsten lass die gesamte Registry weg und mach einfach mysql_connect und mysql_query wie immer. Eine Connection als Variable brauchst du dann nicht mehr. Allerdings ist das ziemlich dämlich sich einen geilen ORM zu basteln und dann die alten prozedualen MySQL-Funktionen zu verwenden. Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
OK. Das wäre dann der Übernächste Schritt. Ich habe mal im Code geguckt. In Contact.php benutze ich $connection gar nicht. Ich müsste also gar nichts speichern in der Registry, sehe ich das richtig? Ich brauche kleine Schritte zum Lernen, wie gesagt.
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Auch wenn ich das nicht für schlau halte; aber ja, das ist dann der richtige Weg. Schrieb ich ja eben schon.
Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Geil. Funktioniert. Ihc habe jetzt die $connection in der registry gespeichert:
PHP-Quellcode:
(Ich habe es auch etwas umbenannt, weil es für mich sinnvoller war.)
include_once("Registry.php");
abstract class DBInit { private static function connect_mysql() { include_once("config.php"); echo "Server: ".$dbserver; $connection = mysql_connect($dbserver, $user, $password); if ($connection == false) { die(mysql_error()); } $db = mysql_select_db("usr_l3s11195_1"); if ($db == false) { die(mysql_error()); } $registry = Registry::getInstance(); $registry->db = $connection; } public static function connect() { register_shutdown_function("DBInit::shutdown"); self::connect_mysql(); } public static function shutdown() { mysql_close(Registry::getInstance()->db); } } Nur bekomme ich nach jeder Abfrage doch ein "Connection closed". Ich dachte, man sollte nicht jedes mal die Verbindung trennen? OK, für mich: - Exceptions: Done - Verbindung ausgelagert: Done Nächstes Ziel: Abfragen mit Parametern. |
AW: [PHP] Klassenstruktur für Adressdatenbank
Du musst noch bei mysql_select_db den Link angeben.
Außerdem dann auch beim mysql_query. Wie wär's wenn du erstmal schaust, dass du die statischen Methoden klar machst? Wenn du magst kann ich dir heute Nachmittag ein Beispiel dazu schreiben. :) Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
PHP-Quellcode:
$query = ....;
myql_query(!query); Zitat:
Im Anhang mal das ganze Projekt, damit du dir einen Überblick verschaffen kannst. |
AW: [PHP] Klassenstruktur für Adressdatenbank
Bin noch nicht dazu gekommen daran weiter zu arbeiten. Ist also noch der aktuelle Stand.
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Zitat:
|
AW: [PHP] Klassenstruktur für Adressdatenbank
Ups, jetzt hab ich dich fast vergessen. :?
Zum mysql_select_db: Schau doch einfach selbst nach wie das geht? ![]() Jedenfalls hab ich hier mal eine kleine Herausforderung für dich. Sag Bescheid wenn du etwas nicht verstehst. Der schöne Teil des Codes sind die zwei letzten Zeilen unten. Diese zeigen, wie man später mit Datenbanken (im Controller) arbeiten kann. Selbstverständlich lässt sich das alles noch erweitern. Die Save Methode ist nicht vollständig und auch nicht getestet, da ich jetzt leider weg muss. Ich wollte dir den Code nur nicht vorenthalten. :) Du brauchst mindestens PHP 5.3 für das "Late static Binding" (get_called_class).
PHP-Quellcode:
Liebe Grüße,
abstract class DB_Table
{ static protected $table = NULL; protected $fields = array(); protected $changed = array(); protected $exists = false; public function __construct(array $fields, $exists = false) { $this->fields = $fields; $this->exists = $exists; } public function __get($name) { return $this->fields[$name]; } public function __set($name, $value) { if ($name == "id") throw Exception("Cannot changed ID. Yet."); array_push($this->changed, $name); return $this->fields[$name] = $value; } public function save() { if ($this->exists and count($this->changed) > 0) { $sql = array(); foreach ($this->changed as $column) { $sql[] = "`" . $key . "` = '" . mysqli_real_escape_string($this->fields[$column]) . "'"; } $sql = "UPDATE `" . $this->table . "` SET " . implode(", ", $sql) . " WHERE `id` = " . intval($this->fields['id']); print($sql); } else { // TODO Insert } } /** * Returns one instance with primary key = $id */ public static function get($id) { $class = get_called_class(); if ($class == __CLASS__) throw new Exception("Cannot call get() directly."); $result = mysql_query("SELECT * FROM `" . $class::$table . "` WHERE `id` = " . intval($id)); return $class::getOne($result); } protected static function getOne($result) { $class = get_called_class(); if ($result === false) throw new Exception("Query faild. " . mysql_error() . " (" . mysql_errno() . ")"); if (mysql_num_rows($result) == 0) throw new Exception("No object matching id " . str($id)); if (mysql_num_rows($result) > 1) throw new Exception("Too many results. Please check table schema."); return new $class(mysql_fetch_assoc($result), true); } protected static function getMultiple($result) { $class = get_called_class(); if ($result === false) throw new Exception("Query faild. " . mysql_error() . " (" . mysql_errno() . ")"); if (mysql_num_rows($result) == 0) throw new Exception("No object matching id " . str($id)); $list = array(); // TODO Verwaltungsklasse für mehrere Reihen! while ($row = mysql_fetch_assoc($result)) { $list[] = new $class($row, true); } return $list; } } class DB_Adressen extends DB_Table { static protected $table = 'adressen'; public function findByName($name) { $name = mysql_real_escape_string($name); $result = mysql_query("SELECT * FROM adressen WHERE name = '" . $name . "'"); return self::getMultiple($result); } } mysql_connect("127.0.0.1", "", ""); mysql_select_db("test"); var_dump(DB_Adressen::get(1)); var_dump(DB_Adressen::findByName("Puff")); Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Hm, sieht sehr gut aus. Muss ich mir nur noch mal genauer angucken. Besten Dank.
|
AW: [PHP] Klassenstruktur für Adressdatenbank
OK, ich glaube, ich habe es verstanden.
Nur, wie muss ich das Formular abschicken, um die Methode save() nutzen zu können? Ich gehe mal davon aus, dass die Eingabefelder genauso benannt sein müssen, wie die Felder in der Datenbank. Aber wie geht es weiter? |
AW: [PHP] Klassenstruktur für Adressdatenbank
![]() Du kannst oben auf "Diff" klicken wenn dich die genauen Unterschiede interessieren. (Auch wenn das bei mir i.M. nicht funktioniert :-? ) Edit:// Ups, ich glaube ich habe deine Frage eben missverstanden. Wenn du das per Formular machen möchtest, dann kannst du der DB_Table Klasse eine Methode "update" verpassen, welche ein assoziatives Array an Daten bekommt und entsprechend setzt. Normalerweise macht man auch für jedes Formular eine Klasse, die entsprechend von einer Basisklasse "Form" erbt. Dort definiert man die Felder des Formulars und welche Datentypen sie besitzen. Man macht dann eine Methode "validate", welche prüft ob alle Ints tatäschlich Ints sind usw. Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Hm hm, hm. Ok, machen wir langsam.
PHP-Quellcode:
Also wenn ich das richtig verstehe, dann wird für jedes geänderte Feld der Schleifenrumpf aufgerufen. Die geänderten Felder kommen in ein Array (__set). OK. Das Array ist ein assoziatives Array. Der Schlüssel ist der Feldname und der Wert, die Eingabe in dem entsprechendem Edit aus dem Formular. In meinem Fall würde das Array dann alle Felder der Tabelle enthalten. Soweit richtig?
public function save() {
if ($this->exists and count($this->changed) > 0) { $sql = array(); foreach ($this->changed as $column) { $sql[] = "`" . $key . "` = '" . mysqli_real_escape_string($this->fields[$column]) . "'"; } $sql = "UPDATE `" . $this->table . "` SET " . implode(", ", $sql) . " WHERE `id` = " . intval($this->fields['id']); print($sql); } else { // TODO Insert } } Ich müsste für jedes Eingabefeld __set aufrufen und dann save. Mal sehen, ob ich das hinbekomme. |
AW: [PHP] Klassenstruktur für Adressdatenbank
Schau doch mal meinen Link an, da habe ich nochmal einiges am Code geändert.
Ansonsten ruft man nicht __set auf, sondern macht einfach
PHP-Quellcode:
. Das ruft automatisch __set auf. :)
$instanz->feld = "wert";
Liebe Grüße, Valentin |
AW: [PHP] Klassenstruktur für Adressdatenbank
Ja, habe ich schon gesehen. Da ist ja auch schon der INSERT Zweig implementiert.
Aber habe ich es richtig verstanden, wie ich die save Methode anwenden muss? |
AW: [PHP] Klassenstruktur für Adressdatenbank
Ich habe noch ein Problem. Wie bekomme ich die Daten aus dem Formular in die DB_Table Klasse?
Mein Formular sieht so aus:
PHP-Quellcode:
Nach dem Abschicken wird in den "save" Zweig der index.php gesprungen:
public function showForm() {
echo "<form action='index.php?action=save' method='GET'>\n"; echo "<input type=\"hidden\" name=\"action\" value=\"save\">\n"; echo "Name: <input name=\"name\" type=\"text\"></input><br>\n"; echo "Vorname: <input name=\"vorname\" type=\"text\"></input>\n"; echo "<br><br>\n"; echo "<input type=\"submit\" value=\"Speichern\"></input>\n"; echo "</form>\n"; }
PHP-Quellcode:
Aber wie fülle ich jetzt das $fields Array aus meiner DB_Adressen Klasse und wie geht die Zuordnung Tabellenfeld und Wert?
case "save":
echo "Name: ".$name; DB_Adressen::save(); break;
PHP-Quellcode:
class DB_Adressen extends DB_Table {
static protected $table = 'adressen_data'; protected $fields = array(); protected $changed = array(); protected $exists = false; public function __construct(array $fields = array(), $exists = false) { $this->fields = $fields; $this->exists = $exists; } public function __get($name) { return $this->fields[$name]; } public function __set($name, $value) { if ($name == "id") throw Exception("Cannot change ID. Yet."); array_push($this->changed, $name); return $this->fields[$name] = $value; } public function save() { echo "Speichern"; } |
AW: [PHP] Klassenstruktur für Adressdatenbank
Dafür macht man sich eine "Form" Klasse und erbt dann eine "Form_NewAddress" Klasse davon. Man könnte das dann so anwenden:
PHP-Quellcode:
Ohne mir jetzt genauer Gedanken über die Implementation gemacht zu haben, würde ich die NewAddress-Form-Klasse ungefähr so machen:
if ($_SERVER['REQUEST_METHOD'] == "POST") {
$form = new Form_NewAddress($_POST); // Formular mit Daten if ($form->is_valid()) { // geht interne Felder durch: is_email(...) && is_plz(...) && ... $new = new DB_Adressen(); $new->set_data($form->cleaned_data); // cleaned_data: Array mit bereinigten Werten (zB "echte" Ints) $new->save(); } else { echo $form->render(); // gibt Fehlermeldung + vorher ausgefüllte Felder aus } } else { $form = new Form_NewAddress(); // leeres Formular echo $form->render(); }
PHP-Quellcode:
Ich hoffe du verstehst was ich meine. Ansonsten sag Bescheid, dann mach ich gern ein detaillierteres Codebeispiel. :thumb:
class Form_NewAddress extends Form
{ // wird von der Vaterklasse im __construct aufgerufen protected function init_fields() { $this->add_field("name", new FormField_VarChar(255)); $this->add_field("email", new FormField_Email()); $this->add_field("irgendwas_mit_regex", new FormField_Regex(".*hier kranken Regex einfügen.*")); } // Weitere Methoden werden alle geerbt. is_valid() geht die Felder durch und füllt // cleaned_data. render() ruft alle render() Methoden der FormField-Instanzen auf // die wiederum den HTML Code zurückgeben. __construct prüft speichert eventuell // mitgegebene Daten in raw_data. Vaterklasse sollte übrigens abstract sein. } DB_Adressen::save() macht übrigens allgemein wenig Sinn. Eine Instanz repräsentiert einen Datensatz der Tabelle. Die Klasse selbst repräsentiert die ganze Tabelle. Speichern kann man eigentlich nur einen Datensatz. Liebe Grüße, Valentin |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:58 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz