Php

Pear DB_DataObject Einsteiger-Tutorial (Php Tutorial)

Tutorial erstellt von TakaBo, letzte Änderung am 04.07.2007


  • 1. Ziel

  • 2. Voraussetzung

  • 3. Warum ORM?

  • 4. Pear Crashkurs

  • 5. Einstieg in DB_DataObject

  • 6. Aussichten



Ziel

Ziel diese Tutorials soll es sein, dem Leser einen Einblick in das Object Relational Mapping (ORM) zu geben. Der Leser sollte danach in der Lage sein eigene kleine Projekt mit Hilfe von ORM abzubilden.  

Voraussetzung

Für dieses Tutorial wird PHP benötigt. Das Tutorial selber wurde mit PHP5 getestet. Ein Funktionieren mit PHP4 kann nicht garantiert werden. Ein Webserver ist optional. Desweiteren benötigen wir ein Datenbankmanagement-System (DBMS) wie z.B. PostgreSQL oder MySQL.  

Warum ORM?

Objektorientiertes Programmieren war und ist nicht nur ein „hype“ unserer Tage, sondern es verspricht auch viele Vorteile gegenüber prozeduralem Programmieren. Z.B. Verstecken der Daten vor anderen Objekten durch eine wohl definierte Schnittstelle (keine unerwartete Manipulation der Daten), auch Blackbox Prinzip genannt. Vererbung von Methoden und Daten an andere Klassen. Bildung von Kompositionen ( Mehrere Klassen werden zu Datentypen einer neuen Klasse ) usw. Zum Einen ermöglicht es die Wiederverwendbarkeit von Code zu erleichtern, zum Anderen hilft die objektorientierte Sicht beim Entwurf einer Software, da wir Mensche in einer objektorientierten Welt leben.

Doch was hat das ganze mit ORM zu tun? Ganz einfach. Irgendwo auf dem Weg von der prozeduralen Programmierung zur objektorientierten Programmierung hat man den Kontakt zu den Datenbanken verloren. Die Darstellung von Datenbeständen in Relationen ist eher was für prozedurale Programme, denn objektorientierte. Umständliche Initialisierungen und Abfragen der DBMS erschweren den Umgang mit Datenbeständen. Besonders in PHP, in der es offensichtlich bei jeder neuen Minor-Versionsnummer eine geänderte Datenbank-API zu geben scheint, wäre es sinnvoll die Datenbankschnittstellen zu abstrahieren, besser noch: Eine einheitliche objektorientierte Schnittstelle anzubieten, um persistente abstrakte Datentypen zu erzeugen. Dieser Vorgang, d.h. das Abbilden von Relationen auf abstrakte Datentypen (bzw deren Objekte), wird als Object Relational Mapping , kurz ORM, bezeichnet.

Pear Crashkurs

DB_DataObject ist ein ORM-Tool, das mit dem PHP-Tool PEAR installiert werden kann. Da PEAR selbst bei den meisten Distributionen dabei ist, erspare ich mir eine explizite Installationsanleitung zu PEAR und widme mich den Paketen von PEAR. Ein Aufruf von pear list in der Konsole gibt darüber Auskunft, ob das Paket DB_DataObject installiert ist.


dsh#pear list
Installed packages, channel pear.php.net:
=========================================
Package Version State
Archive_Tar 1.3.1 stable
Console_Getopt 1.2 stable
DB 1.7.6 stable
DB_DataObject 1.7.15 stable
Date 1.4.6 stable
PEAR 1.4.5 stable
XML_RPC 1.4.4 stable


Sollte DB_DataObject nicht in der Ausgabe auftauchen, muß es nachinstalliert werden.Ganz einfach geht das über den PEAR Befehl install. Da DB_DataObject auf die Pakete Date und DB angewiesen ist, installieren wir erst diese mit:

#pear install Date

und

#pear install DB

Während der Installation werden wir darauf hingewiesen, daß wir auch noch optionale Pakete installieren könnten. Diese sind für dieses Tutorial aber nicht notwendig.

Danach können wir mit  

#pear install DB_DataObject

das ORM-Paket von PEAR installieren.

Häufig kommt es zu Problemen, weil Suse und Co das PEAR-Verzeichnis nicht in den include_path-Schlüssel der php.ini aufgenommen haben. Mit Hilfe von  

#pear config-show  

kann man sich die Konfiguration von PEAR genauer ansehen, die ungefähr so aussehen sollte:

CONFIGURATION (CHANNEL PEAR.PHP.NET):
=====================================
Auto-discover new Channels     auto_discover    <not set>
Default Channel                default_channel  pear.php.net
HTTP Proxy Server Address      http_proxy       <not set>
PEAR server [DEPRECATED]       master_server    pear.php.net
Default Channel Mirror         preferred_mirror pear.php.net
Remote Configuration File      remote_config    <not set>
PEAR executables directory     bin_dir          /usr/local/bin
PEAR documentation directory   doc_dir          /usr/local/share/doc/pear
PHP extension directory        ext_dir          /usr/local/lib/php/20050922
PEAR directory                 php_dir          /usr/local/share/pear
PEAR Installer cache directory cache_dir        /tmp/pear/cache
PEAR data directory            data_dir         /usr/local/share/pear/data
PHP CLI/CGI binary             php_bin          /usr/local/bin/php
PEAR test directory            test_dir         /usr/local/share/pear/tests
Cache TimeToLive               cache_ttl        3600
Preferred Package State        preferred_state  stable
Unix file mask                 umask            22
Debug Log Level                verbose          1
PEAR password (for             password         <not set>
maintainers)
Signature Handling Program     sig_bin          /usr/local/bin/gpg
Signature Key Directory        sig_keydir       /usr/local/etc/pearkeys
Signature Key Id               sig_keyid        <not set>
Package Signature Type         sig_type         gpg
PEAR username (for             username         <not set>
maintainers)
User Configuration File        Filename         /root/.pearrc
System Configuration File      Filename         /usr/local/etc/pear.conf
      

Besonders wichtig ist hierbei die Zeile PEAR directory, da hier der Pfad zum PEAR-Verzeichnis angegeben wird. In der Datei php.ini muß der Pfad im Schlüssel include_path eingetragen werden, in diesem Fall also include_path=“.:/usr/local/share/pear“. Damit ist gewährleistet, daß PHP die PEAR-Pakete später auch findet. Ein weiterer Fallstrick bei SUSE u.a. ist die Tatsache, daß es für php-cli und mod_php getrennte php.ini Dateien gibt. Das kann dazu führen, daß ein php-Programm in der Konsole funktioniert, aber nicht im Apache als mod_php.      


Einstieg in DB_DataObject

DB_DataObject basiert auf DB, dem Datenbankabstraktions-Layer von PEAR. Ich will hier nicht näher darauf eingehen. Es sei nur so viel gesagt: Es ermöglicht einen einheitlichen Zugriff auf Datenbank Management Systeme. So brauch man sich fast keine Gedanken darum zu machen, welches DBMS als Backend läuft, da die API Einheitlich ist. Lediglich der Initialisierungsstring ( auch DSN genannt ) entscheidet über das DBMS. Wen es interessiert, dem sei die Dokumentation auf http://pear.php.net ans Herz gelegt.

Als Beispiel wollen wir eine Datentabelle für Modellautos anlegen. Wir überlegen uns dazu ein mögliches Schema:

Code:
tabellenname=matchbox
artikelnummer:varchar(10); //Primärer Schlüssel, Bedingung nicht NULL, Eindeutig
bezeichnung:varchar(30);
preis:float;



Unter PostgreSQL könnte die Datentabelle mit SQL so aufgebaut werden:

Code:
CREATE TABLE matchbox
(
   artikelnummer varchar(10) NOT NULL,
   bezeichnung varchar(30),
   preis float4,
    PRIMARY KEY (artikelnummer),
) WITHOUT OIDS
TABLESPACE pg_default;
ALTER TABLE matchbox OWNER TO pgsql;


Für MySQL muß das ganze entsprechend angepasst werden. Nun füllen wir die Tabelle mal mit ein paar Datensätzen.

Code:
INSERT INTO matchbox (artikelnummer, bezeichnung, preis) VALUES ('G5550-42', 'Pontiac® Solstice Concept', 12.95);
INSERT INTO matchbox (artikelnummer, bezeichnung, preis) VALUES ('G5550-72', 'Lamborghini Diablo', 15.99);
INSERT INTO matchbox (artikelnummer, bezeichnung, preis) VALUES ('G5550-28', '1970 Mustang Boss 302', 17.95);


Was wir nun haben, ist eine Datenbanktabelle mit ein paar Datensätzen. Und? Das Beste kommt jetzt ;-)

Wir konfigurieren uns das DB_DataObject Paket. Wir benutzen dazu eine INI-Datei, wie sie z.B. auch unter Windows Anwendung findet. In dieser INI-Datei können auch andere Parameter für die Anwendung stehen. Wir beschränken uns hier erstmal nur auf die für DB_DataObject relevanten Schlüssel.

Wir erstellen die Datei system.ini in unserem Arbeitsverzeichnis mit folgendem Inhalt:

Code:
[DB_DataObject]
database    = pgsql://pgsql:@localhost/tutorial
schema_location = /home/work/tutorial/DataObjects
class_location  = /home/work/tutorial/DataObjects
class_prefix    = DO_
generator_strip_schema = 1



Der erste Eintrag in eckigen Klammern gibt an, dass alle Schlüssel danach für das DB_DataObject-Paket gedacht ist. Der Schlüssel database enthält die so genannte DSN (Data Source Name). Sie hat folgenden Aufbau:

<DBMS-Namenskürzel>://<Benutzer>:<Passwort>@<host>/<datenbank>

In unserem Beispiel haben wir das <DBMS-Namenskürzel> mit pgsql belegt. Mögliche andere Werte sind, wenn die entsprechende Extension für PHP mit eingebunden sind:  

dbase  -> dBase
fbsql  -> FrontBase
ibase  -> InterBase
ifx    -> Informix
msql   -> Mini SQL
mssql  -> Microsoft SQL Server
mysql  -> MySQL (für MySQL <= 4.0)
mysqli -> MySQL (für MySQL >= 4.1) (benötigt PHP 5)
oci8   -> Oracle 7/8/9
odbc   -> ODBC (Open Database Connectivity)
pgsql  -> PostgreSQL
sqlite -> SQLite
sybase -> Sybase

(Quelle: http://pear.php.net)


Der <Benutzer> ist in diesem Beispiel pgsql (Default unter FreeBSD bei Verwendung von PostgreSQL, muß für das entsprechende DBMS angepasst werden) mit einem leeren Passwort.

Die Schlüssel schema_location und class_location zeigen DB_DataObject den Ort an, wo es Informationen zu den Datenbanktabellen speichern kann.

Der Schlüssel class_prefix gibt an, welchen Namenszusatz DB_DataObject vor die erzeugten Klassen setzten soll.

generator_strip_schema=1 ist u.a. für PostgreSQL gedacht, um z.B. das Schema „public“ aus dem Namen zu entfernen. Der Sinn ist, daß man nachher die Objekte gleich benamen kann, wie die Datentabelle, also „matchbox“ anstatt „public_matchbox“.


Unsere Verzeichnis-Struktur sollte in etwa so aussehen:

/home/work/tutorial
                |-/DataObjects
                |-system.ini


Jetzt wird createTables.php aufrufen, das sich im Verzeichnis DB/DataObject unterhalb des PEAR-Pfades bedindet. Der Aufruf sollte in etwa folgendes Ergebnis liefern:

dsh# php /usr/local/share/pear/DB/DataObject/createTables.php system.ini
DB_DataObject_Generator   : 0       : CREATING FOR tutorial
DB_DataObject_Generator   : 0       : calling generateDefinitions
DB_DataObject_Generator   : 0       : Generating Definitions file:
DB_DataObject_Generator   : 0       : Writing ini as /home/work/tutorial/DataObjects/tutorial.ini
DB_DataObject_Generator   : 0       : calling generateClasses
DB_DataObject_Generator   : 0       : writing DO_matchbox
DB_DataObject_Generator   : 0       : DONE
dsh#


Im Verzeichnis DataObjects befinden sich zwei neue Dateien :

Matchbox.php  und   tutorial.ini.

Unser erstes Programm

Wir machen uns das ORM jetzt in einem ersten einfachen Programm zu nutzen. Es soll uns den Namen und den Preis des Modells für eine Artikelnummer zurück geben.

Zuerst schreiben wir uns ein Modul, daß die Konfiguration von DB_DataObject für unsere Projekte vor nimmt.

Code:
<?php
  // Dateiname:dbo_config.php
  require_once 'DB/DataObject.php';

  $options = &PEAR::getStaticProperty('DB_DataObject','options');
  $config = parse_ini_file(dirname(__FILE__).'/system.ini',TRUE);
  $options = $config['DB_DataObject'];
?>


Um nun das eigentliche Programm:

Code:
<?php
  // Dateiname: gib.php
  require_once dirname(__FILE__).'/dbo_config.php';

  $car=DB_DataObject::factory('matchbox');
  $car->get('G5550-42');

  echo "Art. Nr:".$car->artikelnummer."n";
  echo "Bez.   :".$car->bezeichnung."n";
  echo "Preis  :".$car->preis."n";
?>


Die generierte Ausgabe sieht in etwa so aus:

dsh#php gib.php
Art. Nr:G5550-42
Bez.   :Pontiac® Solstice Concept
Preis  :12.95

Dieses Beispiel nutzt die Möglichkeit über die Methode get(key) direkt den primären Schlüssel abzufragen. Aber man kann auch eine andere Lösung benutzen:

Code:
<?php
  // Dateiname: gib2.php
  require_once dirname(__FILE__).'/dbo_config.php';

  $car=DB_DataObject::factory('matchbox');
  $car->preis=15.99;

  $num=$car->find();

  if ($num)
  {
    $car->fetch();
    echo "Art. Nr:".$car->artikelnummer."n";
    echo "Bez.   :".$car->bezeichnung."n";
    echo "Preis  :".$car->preis."n";
  }
  else
  {
    echo "Kein Ergebnis gefunden.";
  }
?>


Die Ausgabe dazu sollte das Ergebnis liefern:

dsh#php gib2.php
Art. Nr:G5550-72

Bez.   :Lamborghini Diablo
Preis  :15.99


Es wird ersichtlich, wie einfach Datenbankabfragen gestalltet werden können. Auch Iterationen sind kein Problem mehr, bei denen man unleserliche abenteuerliche Konstrukte entwerfen muß:

Code:
<?php
  //Dateiname: gib3.php
  require_once dirname(__FILE__).'/dbo_config.php';

  $car=DB_DataObject::factory('matchbox');
  $car->whereAdd('preis > 15.00');
  $num=$car->find();

  if ($num){
    while($car->fetch()){
      echo "Art. Nr:".$car->artikelnummer."n";
      echo "Bez.   :".$car->bezeichnung."n";
      echo "Preis  :".$car->preis."nn";
    }
  }
  else
  {
    echo "Kein Ergebnis gefunden!";
  }
?>


Auch hier das Ergebnis nach Aufruf von php gib3.php:

dsh#php gib3.php
Art. Nr:G5550-72
Bez.   :Lamborghini Diablo
Preis  :15.99

Art. Nr:G5550-28
Bez.   :1970 Mustang Boss 302
Preis  :17.95


Aber auch Einfügen und Löschen von Datensätzen stellt für DB_DataObject kein Problem dar.

Code:
<?php
  // Dateiname: setze.php
  require_once dirname(__FILE__).'/dbo_config.php';

  function suche()
  {
    echo "Suche...n";
    $newcar=DB_DataObject::factory('matchbox');
    $newcar->whereAdd('preis < 1.0');
    $num=$newcar->find();
    if ($num)
    {
      $newcar->fetch();
      echo "Art. Nr:".$newcar->artikelnummer."n";
      echo "Bez.   :".$newcar->bezeichnung."n";
      echo "Preis  :".$newcar->preis."nn";
    }
    else
    {
      echo "Keinen Datensatz gefunden!n";
    }
  }

  $car=DB_DataObject::factory('matchbox');

  echo "Objekt anlegenn";
  $car->artikelnummer='B7772-33';
  $car->bezeichnung='VW-Kaefer';
  $car->preis=0.99;
  $car->insert();

  // Suchen
  suche(); //Sollte ein Ergebnis zurück liefern

  echo "Objekt wieder löschenn";
  $car->delete();

  // Suchen
  suche(); //Sollte kein Ergebnis mehr liefern
?>


Die Ausgabe sieht dann etwa so aus:

dsh#php setze.php
Objekt anlegen
Suche...
Art. Nr:B7772-33
Bez.   :VW-Kaefer
Preis  :0.99

Objekt wieder löschen
Suche...
Keinen Datensatz gefunden!

Aussichten

Für den Einstieg sollte das erstmal reichen. Wer neugierig geworden ist, der kann sich die Dokumentation zu DB_DataObject ansehen unter http://pear.php.net/manual/en/package.database.db-dataobject.php.

Besonders interessant wird die Benutzung von DB_DataObject mit dem FormBuilder, der es einem ermöglicht auf relativ einfache Art und Weise Formulare aus Datensätzen aufzubauen, Formulardaten zu Validieren und Daten aus Formularen in Datentabellen abzuspeichern. Da ich selbst intensiv dabei bin in die Materie vorzudringen, könnte zu dem Thema vielleicht noch ein Tutorial herausspringen.

Für Verbesserungsvorschläge und Anmerkungen bin ich hier im Forum erreichbar unter takabo.  

Gruß Chris

>> Allgemeine Fragen oder Probleme mit dem Tutorial? Hier gehts zum Forum!

Impressum / Datenschutzerklärung          © der-Webdesigner.net 2002 - 2008           top ▲