Frage an OOP Experten

dg87

Erfahrenes Mitglied
Guten Morgen liebe Gemeinde,

ich habe eine Frage:

Angenommen wir haben unsere klassisches Beispiel an Pizzalieferanten, wir haben eine Klasse Bestellung und Pizza.
Mich würde interssieren, was vernünftiger ist:
Wenn eine neue Pizza oder Bestellung kommt, soll der Insert in die Datenbank von den beiden klassen aus gemacht werden?
Oder ist es sinnvoller eine allgemeine Klasse für Datenbank Operationen zu bauen, wo von dort aus die Inserts, Deletes und so gemacht werden. Hier sehe ich halt den Vorteil man kann es für mehrere Projekte verwenden und Dynamisch für jede Klasse.

Ich frage nur, weil mich interessiert wie man das in echten Projekten umsetzt. Wenn es eine ganz andere Lösung gibt, bin ich gerne bereit. Glaube mit PDO wäre Möglichkeit zwei schön umzusetzen.

Oben ist nur ein Bespiel, natürlich werden Projekte viel größer und deshalb denke ich dass es mit einer Datenbank Klasse besser ist, oder?

Tipps?

Dankeschön
 
Ich würde eine DB-Klasse nehmen und diese aus den Beiden Klassen anzusteuern. Das SQL selber aber in den Klassen zusammenzusetzen, da diese wieder spezifisch sind.

PHP:
class DB{
	protected static $db;
	public function __construct(){
		//TODO: create DB-Connection and save in self::$db
	}
	public static function execute($sql){
		$instance = new DB();
		return mysql_query($sql, self::$db);
	}
}

class Pizza{
	public function new($name, $preis){
		$sql = "INSERT INTO pizza (name, preis) VALUES ('{$name}', {$preis});";
		DB::execute($sql);
	}
}

class Bestellung{
	public function new($besteller, $pizza){
		$sql = "INSERT INTO bestellung (besteller, pizza) VALUES ('{$besteller}', {$pizza});";
		DB::execute($sql);		
	}
}

Natürlich ist das nur ein abstraktes Beispiel- DB-Klassen gibt es einige gute oder du machst selber etwas Sinnvolles.
 
Eine letzte doofe Frage noch, ich frage deshalb so blöd, weil ich OOP Praxisorientiert lernen will.

Wie ist es denn wenn ein Formular für die Bestellung ausgefüllt und abgeschickt wird.
Soll nach dem 'Absenden' Button gleich ein Objekt von Bestellung erstellt werden und dann die Methode, dass die Bestellung in die DB kommt?
Oder ist es da dann sinnvoll, die Methode vorher in der Klasse als Static zu machen, damit ich kein Objekt erstellen muss, sondern gleich die Bestellung mit Hilfe der Methode in die DB bringe?

Mir gehts halt allgemein darum, wie das läuft, nachdem man ein Formular abgeschickt hat.
 
Um ehrlich zu sein: ich würde deine erste Variante nehmen. Dafür gibt es das schöne Entwurfsmuster ActiveRecord.
PHP:
class ActiveRecord
{
  private $_data = array('new' => array(), 'find' => array());
  private $_connection = null;
  protected static $_table = '';
  
  public function __construct(array $data = array(), $new = true)
  {
    if($new === true) {
      $this->_data['new'] = $data;
    } else {
      $this->_data['find'] = $data;
    }
    $this->_connection = Database::getInstance();
  }
  
  public static function find($query)
  {
    if(is_numeric($query)) {
      $data = $this->_connection->query('SELECT * FROM ' . static::$_table . ' WHERE id = ' . (int) $query);
    } elseif(is_string($query)) {
      $data = $this->_connection->query('SELECT * FROM ' . static::$_table . ' WHERE ' . $query);
    } elseif((is_array($query)) && ($query !== array())) {
      $sql = array();
      foreach($query as $column => $value) {
        $sql[] = $column . ' = "' . $value . '"';
      }
      $data = $this->_connection->query('SELECT * FROM ' . static::$_table . ' WHERE ' . implode(' ', $sql));
    } else {
      return null;
    }
    
    if($data === null) {
      return null;
    }
    
    $result = array();
    foreach($data as $dataset) {
      $result[] = new self($dataset, false);
    }
    
    if(count($result) === 1) {
      return $result[0];
    } else {
      return $result;
    }
  }
  
  public function __get($name)
  {
    if(isset($this->_data['new'][$name])) {
      return $this->_data['new'][$name];
    } elseif(isset($this->_data['find'][$name])) {
      return $this->_data['find'][$name];
    } else {
      return null;
    }
  }
  
  public function __set($name, $value)
  {
    $this->_data['new'][$name] = $value;
  }
  
  public function save()
  {
    $new   = ($this->_data['new'] !== array());
    $exists = ($this->_data['find'] !== array());
    # Die Werte haben sich verändert:
    $diff   = array_intersect_key($this->_data['new'], $this->_data['find']);
    
    if($new && $exists) {
      $this->_connection->query('UPDATE ' . static::$_table . ' SET ...');
    } elseif($new && !$exists) {
      $this->_connection->query('INSERT INTO ' . static::$_table . ' ...');
    }
    
    $this->_data['find'] = array_merge($this->_data['find'], $this->_data['new']);
    $this->_data['new'] = array();
  }
}

class Bestellung extends ActiveRecord
{
  protected static $_table = 'bestellungen';
}

# Kann man jetzt so verwenden:
$bestellung = Bestellung::find('datum = "14.6.2011" AND preis > 15');
$bestellung->preis = 14;
$bestellung->save(); # Preis wurde auf 14 gesetzt!

# oder eine neue anlegen:
$bestellung = new Bestellung(array('preis' => 14.5, 'posten' => 16, 'datum' => '12.4.2011'));
$bestellung->save(); # Bestellung gespeichert
 
Entwurfsmuster :-)
Das ist eine Alternative die ich mir anschaue bzw. anschauen muss, weil ich aktuell das Buch PHP Design Patterns lese und denke da wirds dabei sein.
Vielen Dank für die Vorschläge.

Jetzt bleibt nur noch meine Formular Frage, die mich interessieren würde.

Edit: Eigentlich ist die Formularfrage ja auch schon beantwortet, wenn ich grad richtig sehe :--)

Was hast du dann hier für eine DB Klasse?
wegen dem
Code:
Database::getInstance();

du hast dann
Code:
$this->_connection->query(..)

D.h. du hast in der Klasse Database dann ganz normal eine Methode query oder?
 
Zuletzt bearbeitet:
Am Meisten mache ich das so, dass ich es noch weiter aufteile als im Beispiel da oben.
So habe ich eine Klasse Pizza. Das entspricht einem Datensatz.
Dann eine Klasse PizzaFactory. Diese verwaltet die Pizzas gegenüber der DB. Sie erstellt zB. eine Liste (array) mit Pizzas aus der DB, trägt Pizzas in die DB ein etc.

PHP:
class PizzaFactory{
	public static function insertPizzaIntoDB(Pizza $pizza){
		$sql = "INSERT INTO pizza (name, preis) VALUES ('{$pizza->name}', {$pizza->preis}";
		DB::execute($sql);
	}
	public static function getPizzasFromDB($where=NULL){
		$sql = 'SELECT * FROM pizza'.(!is_null($where) ? " WHERE {$where}" : "");		
		$result = DB::execute($sql);;
		$pizzas = array();
		while($row = mysql_fetch_assoc){
			$pizzas[] = new Pizza($row['name'], $row['preis']);
		}
		return $pizzas;
	}
}

class Pizza{
	public $name;
	public $preis;
	public function __construct($name = NULL, $preis = NULL){
		$this->name = $name;
		$this->preis = $preis
	}
	//TODO: weitere Pizza-Spezifische Methoden.
}

//Alle Pizzas auselsen
$allePizzas = PizzaFactory::getPizzasFromDB();
var_dump($allePizzas);
//Neue Pizza hinzufügen
PizzaFactory::insertPizzaIntoDB(new Pizza('TestPizza', 123));
//Wieder alle Pizzas auslesen. Die neue Pizza müsste nun dabei sein.
$allePizzas = PizzaFactory::getPizzasFromDB();
var_dump($allePizzas);
 
an Yaslaw: Ich glaube, dass man bestimmt auch beide Entwurfsmuster miteinander verbinden kann ohne das man auf die Factory direkt zugreift. Aber man kann das hier generell auch ins quasi Unendliche treiben, wenn man nur mal bedenkt, dass man auch noch die Relationen zwischen mehreren Objekten definiert oder Validationsregeln oder das Hinzufügen von Objekten zu anderen Objekten (was mit den Relationen zusammen hängt) oder das man den Tabellennamen automatisch festlegt. Mein Lieblingsprojekt ist in der Hinsicht wieder mal Ruby on Rails, welche das beinahe zur Perfektion getrieben haben.
 
Also nochmal danke für tipps.

Wie oben schon gefragt wie ist es denn in der Praxis bei Formularen? Angenommen der user hat seine Bestellung eingegeben und er klickt auf submit.
Wird danach ein Objekt Bestellung mit Hilfe der Daten ($_POST) erstellt und dann über eine Methode in die DB gespeichert?
Ich mein dafür hab ich ja die Klasse oder gibt's da auch wieder eine bessere alternative ?
 
Bei Webseiten hat sich das MVC-Pattern durchgesetzt (Model-View-Controller), welches ein striktes Trennen von Daten, Anzeige und Steuerung bewirkt. Dabei entscheidet der Controller, welches View bei einem Aufruf verwendet wird und mit welchen Daten dieses View befüllt. Die Daten kommen aus einem oder mehreren Modellen. Und diese Models sind jetzt das, was für dich in erster Linie jetzt wichtig ist. Wenn du das darüber lösen willst, ist mein Ansatz, also das ActiveRecord-Pattern, ein sehr guter Ansatz. In diesem wird nur innerhalb des Objektes mit einer Datenbankklasse gearbeitet. Durch Vererbung kannst du auch eine Grundklasse bilden und im Nachhinein musst du in keiner deren Kindklassen jemals direkt mit der Datenbank arbeiten, da die Abfragen automatisch generiert werden.
 
Ok MVC hab ich ja schon gehört.
Vielen Dank nochmal.
Ich werde mir erstmal nochmal alles über MVC durchlesen und das Active Record auch nochmal genauer anschauen, das finde ich eine schöne Lösung.
 
Zurück