by:

In der Regel programmieren wir ja, um anderen die Arbeit leichter zu machen, bzw. erst zu ermöglichen.
Heute möchte ich einen Weg vorstellen, wie wir uns das Leben etwas leichter machen können.
Ich habe dazu zwei Klassen Online gestellt ClassCreater und TemplateCreater.
Wie der Name schon sagt, erstellt dieses Projekt automatisch Klassen und das dazugehörige Template.
So enthält die damit generierte Klasse alle nötigen Methoden um Daten
in einer Datenbank anzulegen, zu bearbeiten und zu löschen.

Das Projekt befindet sich zwar noch im Entwicklungsstadium, dennoch ist der generierte PHP Code
bereits voll funktionstüchtig.

Die Klassen sowie das Template werden anhand eines create table statements generiert->

BSP:

create table contact (
    id int(12) unsigned not null auto_increment,
    firstname varchar(255) default null,
    lastname varchar(255) default null,
    email varchar(255) default null,
    birthday datetime NOT NULL default '0000-00-00 00:00:00',
    comment text,
    PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


Und dazu passend hier die generierte Klasse:
 

Update: Die Security issues sollten jetzt behoben sein !

Code

<?php
    
    
class contact extends BaseApp {
    
    
    
    /**
         * @var int
         */
    
    public $id 0;
    
    
    /**
         * @var string
         */
    
    public $firstname '';
    
    
    /**
         * @var string
         */
    
    public $lastname '';
    
    
    /**
         * @var string
         */
    
    public $email '';
    
    
    /**
         * @var string
         */
    
    public $birthday '';
    
    
    /**
         * @var string
         */
    
    public $comment '';
    
    
    protected $db;
    
    
        
        
/**
         * The constructer
         */
    
    public function __construct ($id '')
    
    {
    
        if (!isset($this->db))
    
           $this->db parent::getInstance();
    
    
        if (!empty($id))
    
        {
    
           $this->id $id;
    
           $this->get();
    
        }
    
    }
    
    
    
    /**
         * Sanitize a input array
         *
         * @param array $data
         * @return array
         */
    
    public function check($data '')
    
    {
    
        $check = array(
    
        'id' => FILTER_SANITIZE_NUMBER_INT,
    
        'firstname' => FILTER_SANITIZE_STRING,
    
        'lastname' => FILTER_SANITIZE_STRING,
    
        'email' => FILTER_SANITIZE_STRING,
    
        'birthday' => FILTER_SANITIZE_STRING,
    
        'comment' => FILTER_SANITIZE_STRING
            
);
    
        return filter_var_array($data$check);
    
    }
    
    
    
    /**
         * Delete a element in the Database
         */
    
    public function del ()
    
    {
    
        if (empty($this->id) || !is_numeric($this->id))
    
            return false;
    
    
        $sql "DELETE FROM contact WHERE id = :id";
    
        $stmt $this->db->dbh->prepare($sql);
    
        $stmt->bindValue(':id'$this->idPDO::PARAM_INT);
    
        $stmt->execute();
    
    }
    
    
    
    /**
         * Get a list of objects
         *
         * @param array $data optional if you like to get only a subset of data
         *
         * @return obj
         */
    
    public function get_list ($data '')
    
    {
    
        $sql "SELECT c.id, c.firstname, c.lastname, c.email, c.birthday, c.comment FROM contact as c";
    
        if (is_array($data))
    
        {
    
            $data $this->check($data);
    
            $sql .= " WHERE";
    
            foreach ($data as $key => $value)
    
            {
    
                if ($value)
    
                    $sql .= " c.$key = '$value' and";
    
            }
    
            $sql substr($sql0, -4);
    
        }
    
        $stmt $this->db->dbh->query($sql);
    
        $obj $stmt->fetchALL(PDO::FETCH_CLASS'contact');
    
        return $obj;
    
    
    }
    
    
    
    /**
         * Get one Dataset from the db
         */
    
    public function get ()
    
    {
    
        if (empty($this->id) || !is_numeric($this->id))
    
            return false;
    
    
        $sql "SELECT c.id, c.firstname, c.lastname, c.email, c.birthday, c.comment FROM contact as c WHERE
            c.id = 
$this->id";
    
        $stmt $this->db->dbh->query($sql);
    
        $result $stmt->fetch(PDO::FETCH_ASSOC);
    
        foreach ($result as $key=>$val)
    
        {
    
            $this->$key=$val;
    
        }
    
    }
    
    
    
    /**
         * The save method is responsability for
         * saving and updating a dataset
         */
    
    public function save ()
    
    {
    
        if (empty($this->id))
    
        {
    
            $sql 'INSERT INTO contact  (firstname, lastname, email, birthday, comment) VALUES
                (:firstname, :lastname, :email, :birthday, :comment)'
;
    
            $stmt $this->db->dbh->prepare($sql);
    
        }
    
        else
    
        {
    
            $sql 'UPDATE contact set
                 firstname = :firstname,
                 lastname = :lastname,
                 email = :email,
                 birthday = :birthday,
                 comment = :comment'
;
    
            $sql .= " WHERE id = :id";
    
            $stmt $this->db->dbh->prepare($sql);
    
            $stmt->bindValue(':id'$this->idPDO::PARAM_INT);
    
        }
    
        $stmt->bindValue(':firstname'$this->firstnamePDO::PARAM_STR);
    
        $stmt->bindValue(':lastname'$this->lastnamePDO::PARAM_STR);
    
        $stmt->bindValue(':email'$this->emailPDO::PARAM_STR);
    
        $stmt->bindValue(':birthday'$this->birthdayPDO::PARAM_STR);
    
        $stmt->bindValue(':comment'$this->commentPDO::PARAM_STR);
    
        $stmt->execute();
    
    }
    }
    
?>


Ich denke das die automatisch generierte Klasse relativ übersichtlich und verständlich gehalten ist,
dazu passend hab ich auch noch ein kleines Bsp. Script wie man nun diese Klasse benutzen kann.

Code
<?
    include('./inc/class/BaseApp.php');
    include('./inc/class/contact.php');
    
    # ein eintrag erstellen
    $new_contact = new contact();
    $new_contact->firstname = "andreas";
    $new_contact->save();
    
    # ein eintrag aktualisieren
    $contact = new contact(1);
    $contact->firstname = "andreas";
    $contact->lastname = "beder";
    $contact->save();
    
    # nun laden wir eine liste, mit gewissen eigenschaften
    $list = $contact->get_list(array("firstname" => "andreas", "lastname" => "beder"));
    foreach($list as $obj)
    {
        # das aktualisieren geht ganz einfach
        $obj->email="andreas@codejungle.org";
        $obj->save();
    
        # ebenso das löschen
        $obj->del();
    }
    
    ?>
    


Wer es selber mal ausprobieren oder sich daran beteiligen mag, kann sich das Projekt hier herunterladen:

svn co svn://codejungle.org/sourcemagic

Das Projekt ist wie gesagt noch nicht fertig, so benötigt das generieren von HTML Templates noch etwas mehr Zuwendung.
Ich hoffe aber, dass ich das in den kommenden Wochen und vielleicht mit deiner Hilfe in den Griff bekomme.

An dieser Stelle möchte ich auch noch die bekannten Object-Relational Mapper erwähnen,
Doctrine und Propel, welche beide sehr umfangreiche Funktionen zur Verfügung stellen.
Wer mehrere Tabellen verbinden möchte und komplexe Anfragen bewältigen muss ist hier gut bedient.

Man sollte allerdings immer bedenken, dass bei Applikationen, die sehr hohe Last bewältigen müssen, ein zusätzlicher layer
meistens mehr Komplexität bedeutet und ausserdem oft auf Kosten der Performance geht.

Mein Projekt bietet im Vergleich zu Doctrine und Propel wesentlich weniger Funktionen,
bei mir werden einfache C.R.U.D (Create, Read, Update und Delete) Methoden automatisch generiert,
was im wesentlichen uns Programmierern etwas Schreibarbeit abnehmen soll, die Applikationslogik
müssen wir natürlich weiterhin selbst erstellen.

Wer mit mir das Projekt weiterentwicklen möchte, schreibt am Besten einfach eine kurze Mail, ich werde dann
bei Bedarf SVN Zugang zur Verfügung stellen.

Ich freue mich natürlich auch über Verbesserungsvorschläge und Kommentare.

Happy Hacking

Andreas



Name:
Hallo Daniel,

erst mal danke das du dir Zeit genommen hast und mir dein Feedback geschrieben hast.
Ich gebe dir recht das Propel oder Doctrine sicher zu bevorzugen sind, immerhin existieren sie schon wesentlich länger, haben eine größere Community und haben mit Sicherheit mehr Features!
Natürlich könnte ich die DAO Funktionen auch zur runtime generieren, dann würde ich der Klasse nur noch den Tabellennamen sagen, die schaut
nach welche Properties Sie hat und stellt mir dann die DAO Funktionen zur Verfügung.
Ein Freund von mir hat auch genau das gemacht, dann hat man aber das Problem, das die IDE die Properties nicht kennt
und ein dann wenige Hilfestellungen geben kann (gleiches Problem hat man bei Drupal und Wordpress übrigends auch).
Okay man könnte sicher eine art table model description anlegen und der IDE beibringen diese zu verstehen..

Am Ende des Tages bleibt jeden selbst überlassen was er verwendet, null mehrwert find ich als Kritik etwas überzogen,
immerhin spare ich mir doch ein Haufen schreib Arbeit.
Das es besser, schönere, schnellere Wege gibt, darüber können wir gerne Diskutieren.

Grüße
Andreas



Name:
Hallo,

u, ehrlich zu sein ist das ganze vollkommen unnötig. Es bringt absolut keinen Mehrwert. Außerdem werden hier DAO Funktionen und Table Properties, also Model Eigenschaften in eine Klasse geknallt.

Desweiteren gefallen mir die public Properties nicht.

ICh würde das ganze umschreiben. Und eine Klasse nicht anhand eines Create Statements erstellen, sondern anhand der Tabellen die in der Datenbank sind. Das heißt, es gibt 2 brauchbare Wege.

1.) Du erstellst deine Model Klasse und führst diese z.B. über die Konsole aus und erstellst dir damit deine Datenbank Tabellen.

2.) Die Datenbank Tabellen existieren schon und du erstellst deine Modelklassen anhand dieser bestehenden Tabellen.

Um DAO bzw. Repository Klassen und Methoden zu nutzen würde auf Fuktionalitäten wie Propel oder Doctrine setzen, die im übrigen das von mir vorher angesprochene schon mitbringen.

Nichts für ungut und bitte nicht böse sein, aber wie schon erwähnt hat das ganze sbsolut null Mehrwert und wirklichen Sinn.

Gruß litterauspirna aus dem php.de Forum.

Name:
hi sven,

ich habe gerade den object generator umgeschrieben, jetzt sollten die methoden soweit sicher vor sql injections sein.

vielen dank f?r dein feedback !

lg
andreas

Name:
Anf?lligst f?r SQL-Injection - und zwar in allen Funktionen! ?bel! Und das sogar, obwohl ein Versuch mit Prepared Statements unternommen wurde.