Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   [PHP] Klassenstruktur für Adressdatenbank (https://www.delphipraxis.net/166235-%5Bphp%5D-klassenstruktur-fuer-adressdatenbank.html)

Luckie 3. Feb 2012 21:11


[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.

generic 3. Feb 2012 23:06

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.

Valle 3. Feb 2012 23:18

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:
$myList = Contact::byCountry('de')->limit(0, 20);
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.

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

Luckie 4. Feb 2012 02:13

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.

webcss 4. Feb 2012 09:19

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Zitat:

Zitat von Luckie (Beitrag 1149153)
@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.

Dann bau Dir Dein eigenes Framework. Vor zwei Jahren stand ich auch vor diesem Problem, hatte keine Ahnung von PHP, und hab nach langen Recherchen mein eigenes Framework gebastelt. Nebenbei habe ich damit MVC erstmal begriffen.
Ausgegangen bin ich u.a. an-mvc-framework-in-799-bytes/ hiervon, und habe mithilfe von diversen Tutorials mein eigenes gebaut.
Wenn Du die Möglichkeit hast, solltest Du Dir auch mal MongoDB ansehen, ideal für Adressen usw.

generic 5. Feb 2012 15:58

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Doctrine als orm hat sich im PHP Bereich ziemlich verbreitet:
http://www.doctrine-project.org/

Luckie 5. Feb 2012 23:31

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Klingt gut. auch wenn ich es selber bastele, werde ich mir das angucken.

Valle 6. Feb 2012 06:23

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Zitat:

Zitat von Luckie (Beitrag 1149393)
Klingt gut. auch wenn ich es selber bastele, werde ich mir das angucken.

Andersrum wäre schlauer, erst gucken, dann machen. Aber sonst gute Idee. :)

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

Luckie 8. Feb 2012 16:06

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:
<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>
Es kommen noch ein paar Suchabfragen dazu und die Datenbank hat so um die 20 Felder.

Könnte man auch noch was verbessern oder vereinfachen? Oder könnte ich irgendwo Probleme bekommen?

Valle 8. Feb 2012 18:37

AW: [PHP] Klassenstruktur für Adressdatenbank
 
  • class Contact extends DB_Exception? Ich denke das war nicht beabsichtigt, oder?
  • Die Kontakte-Klasse sollte die Verbindung zu MySQL nicht selbst aufbauen.
  • Man schließt die MySQL-Verbindung auch nicht im Destruktor dieser Klasse, sondern am Ende des Programms.
  • Es empfiehlt sich auch eine abstrakte Bibliothek zu verwenden (PDO)
  • Damit mindert man auch das Risiko an SQL-Injections, die du hier auch eingebaut hast; Parameter verwenden!
  • Dein Exception-Handling ist etwas ungünstig. Mit einer richtigen Bibliothek geht das schlauer (ich habe einen Wrapper geschrieben, der automatisch eine Exception wirft, wenn ein Query fehlschlägt) Normalerweise werden diese an der richtigen Stelle erzeugt und bis zur obersten Instanz, einem Exception-Handler, durchgereicht. Hier kann man fein auf eine DEBUG-Variable prüfen und ggf. eine Meldung ausgeben oder gar eine Mail schicken.
  • Statt all die Felder zu kopieren, solltest du Getter und Setter verwenden.
  • Dein MVC ist nicht wirklich eins. Dein View übernimmt Exception-Handling und weiß zu viel vom Model. Einen Controller hast du nicht wirklich, bzw. mischst ihn mit dem eigentlichen View (HTML-Code).
  • Wenn du glücklich werden willst, verwende eine Template-Engine. Die kann man auch leicht selbst machen
  • Als kleiner Tipp: In PHP-Dateien ohne HTML-Code muss man die PHP-Klammer nicht schließen. Nutze das aus, denn damit spart man sich die ein oder andere Leerzeile im Quelltext, welche später (beim Setzen von Cookies und anderen Headers) Kopfschmerzen bereitet.
  • Als Anregung könnte ich den Zend Framework Coding Style Guide (o.ä.) empfehlen!

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:
<?php $answer = 42;
Liebe Grüße,
Valentin

Luckie 8. Feb 2012 18:53

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Zitat:

Zitat von Valle (Beitrag 1149968)
class Contact extends DB_Exception? Ich denke das war nicht beabsichtigt, oder?

Eigentlich schon. Oder wie kann ich sonst eigene, spezifische Exceptions werfen?

Zitat:

Die Kontakte-Klasse sollte die Verbindung zu MySQL nicht selbst aufbauen.
Na ja, Ich wollte es erst nur mit einer Klasse mache, deswegen der Verbindungsaufbau an dieser Stelle. Wo wäre es denn günstiger?

Zitat:

Man schließt die MySQL-Verbindung auch nicht im Destruktor dieser Klasse, sondern am Ende des Programms.
Hm. Es ist also ungünstig jedes mal wieder eine Verbindung aufzubauen und zu trennen?

Zitat:

Es empfiehlt sich auch eine abstrakte Bibliothek zu verwenden (PDO)
Habe ich mit Absicht vermieden.

Zitat:

Statt all die Felder zu kopieren, solltest du Getter und Setter verwenden.
Ich war erst mal zu faul die Getter und Setter zu schreiben. Leider hab eich keine IDE welche sie automatisch aus den privaten Feldern erzeugt.

Zitat:

Dein MVC ist nicht wirklich eins. Dein View übernimmt Exception-Handling und weiß zu viel vom Model. Einen Controller hast du nicht wirklich, bzw. mischst ihn mit dem eigentlichen View (HTML-Code).
Sollte es auch gar nicht sein.

Zitat:

Mach deine Klassen kleiner und dümmer, dafür aber mehr davon. :-)
Mal schauen, ob ich das hinbekomme.

Danke für die Tipps und Anregungen.

Valle 8. Feb 2012 19:56

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Zitat:

Zitat von Luckie (Beitrag 1149969)
Zitat:

Zitat von Valle (Beitrag 1149968)
class Contact extends DB_Exception? Ich denke das war nicht beabsichtigt, oder?

Eigentlich schon. Oder wie kann ich sonst eigene, spezifische Exceptions werfen?

Dein Kontakt ist doch keine Exception, sondern eine Tabelle, bzw eine Zeile dieser. Du wirfst ja keinen Kontakt im Fehlerfall, sondern eine extra angelegte Exception. Normalerweise hat man Exceptions wie QueryFailed oder EmptyResult oder sowas. Diese werden von der Vaterklasse des Kontaktes geworfen und jeweils als eigene Klasse implementiert, denn sowas braucht man bei jeder Klasse. Man hat dann für jede Klasse, und wenn sie noch so klein ist, eine eigene Datei. Ich schlage eine DB_Exception Klasse vor (erbt von Exception) und dann die genannten EmptyResult usw. Exceptions, welche von der DB_Exception erben. getById (oder einfach get) sollte auch nicht vom Kontakt selbst implementiert sein, denn eine ID sollte jede Tabelle haben. (m:n zählt nicht)

Zitat:

Zitat von Luckie (Beitrag 1149969)
Zitat:

Die Kontakte-Klasse sollte die Verbindung zu MySQL nicht selbst aufbauen.
Na ja, Ich wollte es erst nur mit einer Klasse mache, deswegen der Verbindungsaufbau an dieser Stelle. Wo wäre es denn günstiger?

MySQL-Verbindungen speichere ich immer in einer Registry. Diese ist ein Singleton und stellt eigentlich nur ein assoziatives Array dar. Es gibt also nur eine Registry im Programm.
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 von Luckie (Beitrag 1149969)
Zitat:

Man schließt die MySQL-Verbindung auch nicht im Destruktor dieser Klasse, sondern am Ende des Programms.
Hm. Es ist also ungünstig jedes mal wieder eine Verbindung aufzubauen und zu trennen?

Ja natürlich! Was hast du denn gedacht? Für jeden Query Verbindung neu aufbauen und wieder beenden? Eine Verbindung pro Seitenaufruf reicht völlig aus. Es gibt Leute, die gehen dazu über persistente Verbindungen aufzubauen. Diese bauen einmal eine Verbindung auf, welche dann bis zum nächsten Neustart des Webserver aufrecht erhalten bleibt.

Zitat:

Zitat von Luckie (Beitrag 1149969)
Zitat:

Es empfiehlt sich auch eine abstrakte Bibliothek zu verwenden (PDO)
Habe ich mit Absicht vermieden.

Schade, warum? Du weißt dass du SQL-Injections riskierst?

Zitat:

Zitat von Luckie (Beitrag 1149969)
Zitat:

Statt all die Felder zu kopieren, solltest du Getter und Setter verwenden.
Ich war erst mal zu faul die Getter und Setter zu schreiben. Leider hab eich keine IDE welche sie automatisch aus den privaten Feldern erzeugt.

Das hast du nicht richtig verstanden. Du machst dein Query und holst die Daten des Kontakts. Diese speicherst du als assoziatives Array oder Objekt in ein privates Feld, mit Namen data oder so. Dann machst du zwei Methoden __get und __set. Beispiel:
PHP-Quellcode:
 function __get($name) { return $this->data->$name; }
Zitat:

Zitat von Luckie (Beitrag 1149969)
Zitat:

Dein MVC ist nicht wirklich eins. Dein View übernimmt Exception-Handling und weiß zu viel vom Model. Einen Controller hast du nicht wirklich, bzw. mischst ihn mit dem eigentlichen View (HTML-Code).
Sollte es auch gar nicht sein.

Schade, warum?

Zitat:

Zitat von Luckie (Beitrag 1149969)
Zitat:

Mach deine Klassen kleiner und dümmer, dafür aber mehr davon. :-)
Mal schauen, ob ich das hinbekomme.

Sicher schaffst du das. Wir helfen dir dabei! :-)

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

Namenloser 8. Feb 2012 20:16

AW: [PHP] Klassenstruktur für Adressdatenbank
 
[OT]
Zitat:

Zitat von Valle (Beitrag 1149398)
Zitat:

Zitat von Luckie (Beitrag 1149393)
Klingt gut. auch wenn ich es selber bastele, werde ich mir das angucken.

Andersrum wäre schlauer, erst gucken, dann machen. Aber sonst gute Idee. :)

Kommt glaube ich darauf an, was für ein Typ man ist. Manche lernen besser, indem sie Code von anderen studieren, andere lernen besser, indem sie selbst welchen schreiben/versuchen etwas nachzubauen. Ich gehöre selbst zur zweiten Gruppe. Oft wird einem nämlich erst dann klar, warum bestimmte Dinge bei anderen Frameworks/Libs/Was-auch-immer auf eine bestimmte Weise gelöst wurden. Ich hatte auf diese Weise jedenfalls schon einige Aha-Erlebnisse.
[/OT]

Valle 8. Feb 2012 20:24

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

Luckie 9. Feb 2012 14:31

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.

Luckie 9. Feb 2012 15:47

AW: [PHP] Klassenstruktur für Adressdatenbank
 
So, meine Exceptionklasse sieht jetzt erst mal so aus:
Code:
<?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);
      }
   }
?>
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.

Valle 9. Feb 2012 19:21

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Zitat:

Zitat von Luckie (Beitrag 1150154)
Ich habe gelesen, dass man den Konstruktor auf alle Fälle überschreiben und dort den Parent-Konstruktor aufrufen soll.

So'n Quatsch. Lass das mal. o0 (Oder mach's von mir aus ein Mal in der Vaterklasse, aber nicht jedes mal)

Btw, PHP-Klammer bei PHP-Code bitte weglassen, dann funktioniert das Highlighting. :)

PHP-Quellcode:
class DBEXception_QueryFailed extends DBException
{}
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^^)

Zitat:

Zitat von Luckie (Beitrag 1150154)
Ich denke mal, so hast du dir das vorgestellt.

Perfekt. :)

Und hier mal eine einfache und ungetestete Implementation der Registry:

PHP-Quellcode:
// 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();
Liebe Grüße,
Valentin

Luckie 9. Feb 2012 20:54

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.

Valle 9. Feb 2012 20:55

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Richtig, dazu ist es da. :)

Liebe Grüße,
Valentin

Luckie 9. Feb 2012 20:56

AW: [PHP] Klassenstruktur für Adressdatenbank
 
OK, dann hab eich es verstanden. ;)

Luckie 9. Feb 2012 22:10

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Ein kleines Verständnisproblem hab eich noch.

PHP-Quellcode:
      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 =
      }
so stelle ich die Verbindung zur Datenbank her.

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')); ?

Valle 9. Feb 2012 22:26

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

Luckie 9. Feb 2012 22:29

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.

Valle 9. Feb 2012 22:33

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Zitat:

Zitat von Luckie (Beitrag 1150236)
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.

Mal ganz ehrlich: Ich glaube kaum dass dein Hoster kein MySQLi hat. Das ist standardmäßig bei der PHP-Linux-Installation dabei. MySQLi ist nur die Bibliothek dazu. Der MySQL Server ist genau der gleiche. Also sicher dass es kein MySQLi gibt? Einfach mal "$bla = new mysqli(...);" austesten. Wenn das wirklich nicht geht, dann rate ich dir von ganzen Herzen von diesem Provider ab! Aber ich glaube eher dass du da was verwechselst.

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

Luckie 9. Feb 2012 22:40

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.

Valle 9. Feb 2012 22:41

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

Luckie 9. Feb 2012 23:52

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Geil. Funktioniert. Ihc habe jetzt die $connection in der registry gespeichert:

PHP-Quellcode:
   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);
      }

   }
(Ich habe es auch etwas umbenannt, weil es für mich sinnvoller war.)

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.

Valle 10. Feb 2012 09:18

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

Luckie 10. Feb 2012 10:13

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Valle (Beitrag 1150268)
Du musst noch bei mysql_select_db den Link angeben.
Außerdem dann auch beim mysql_query.

Bitte mal zeigen. Und in der Kontaktklasse benötige ich nichts aus DBInit. Das geht auch so:
PHP-Quellcode:
$query = ....;
myql_query(!query);

Zitat:

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. :)
OK. Und ich bin keine Frau, ich mag immer. ;)

Im Anhang mal das ganze Projekt, damit du dir einen Überblick verschaffen kannst.

Luckie 11. Feb 2012 13:43

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Bin noch nicht dazu gekommen daran weiter zu arbeiten. Ist also noch der aktuelle Stand.

ibp 11. Feb 2012 14:30

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Zitat:

Zitat von Luckie (Beitrag 1150285)
Zitat:

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. :)
OK. Und ich bin keine Frau, ich mag immer. ;)

5 Bit in das Chauvi Register!

Valle 11. Feb 2012 14:35

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? Wink mit Zaunpfahl.

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:
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"));
Liebe Grüße,
Valentin

Luckie 11. Feb 2012 14:50

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Hm, sieht sehr gut aus. Muss ich mir nur noch mal genauer angucken. Besten Dank.

Luckie 11. Feb 2012 21:25

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?

Valle 11. Feb 2012 21:29

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Guggst du hier. ;-)

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

Luckie 11. Feb 2012 22:07

AW: [PHP] Klassenstruktur für Adressdatenbank
 
Hm hm, hm. Ok, machen wir langsam.

PHP-Quellcode:
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
         }
      }
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?

Ich müsste für jedes Eingabefeld __set aufrufen und dann save.

Mal sehen, ob ich das hinbekomme.

Valle 11. Feb 2012 23:19

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:
$instanz->feld = "wert";
. Das ruft automatisch __set auf. :)

Liebe Grüße,
Valentin

Luckie 12. Feb 2012 10:18

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?

Luckie 6. Mär 2012 15:10

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:
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";
      }
Nach dem Abschicken wird in den "save" Zweig der index.php gesprungen:
PHP-Quellcode:
case "save":
               echo "Name: ".$name;
               DB_Adressen::save();
               break;
Aber wie fülle ich jetzt das $fields Array aus meiner DB_Adressen Klasse und wie geht die Zuordnung Tabellenfeld und Wert?
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";
         
      }

Valle 6. Mär 2012 15:32

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:
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();
}
Ohne mir jetzt genauer Gedanken über die Implementation gemacht zu haben, würde ich die NewAddress-Form-Klasse ungefähr so machen:

PHP-Quellcode:
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.

}
Ich hoffe du verstehst was ich meine. Ansonsten sag Bescheid, dann mach ich gern ein detaillierteres Codebeispiel. :thumb:

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 18:18 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz