php VO en DAO

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Beste mensen,

om toch wat meer structuur aan te brengen in mijn code ben ik me nu eens aan het verdiepen in VO's en DAO's. Echter om toch te voorkomen dat ik veelvuldig dezelfde code aan het kloppen ben (hoewel ik weet dat je VO's en DAO's kunt laten genereren op basis van je tabelstructuur) wil ik toch een basis object maken. Hieronder een stukje van de code.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class UserVO extends ObjectVO {

    public $object_field = array();
    
    public function __construct($id=false)
    {
        $this->object_field['ID']               = array('dbfield' => "user_id",             'vartype' => "int",     'length' => 50 );   
        $this->object_field['Username']         = array('dbfield' => "user_username",       'vartype' => "string",  'length' => 20 );   
        $this->object_field['Password']         = array('dbfield' => "user_password",       'vartype' => "string",  'length' => 20 );   
        $this->object_field['Gender ']          = array('dbfield' => "user_gender",         'vartype' => "string",  'length' => 30 );   
        $this->object_field['Firstname']        = array('dbfield' => "user_firstname",      'vartype' => "string",  'length' => 30 );   
        $this->object_field['Prefix ']          = array('dbfield' => "user_prefix",         'vartype' => "string",  'length' => 30 );   
        $this->object_field['Lastname']         = array('dbfield' => "user_lastname",       'vartype' => "string",  'length' => 30 );   
    }

}



class ObjectVO {
    
    public $changed_values = array();
    public $original_values = array();

    public function __construct()
    {
        print_r( $this->object_field );
    }
    
    private function __init() 
    {

    }   


    public function __set($property, $value)
    { 
        // check if property is mapped with database
        if ( $this->existProperty($property) )  { 
            
            // check if property has valid value
            if ( $this->validatePropertyValue($property, $value) )  {   
                $this->changed_values[$property] = $value;
            }
        }
    }
}


tegelijkertijd heb ik ook 2 DAO's: 1 voor de specifieke class en 1 ObjectDAO waarin de gebruikelijke get / save / delete methods zitten. Die laatste wordt gebruikt voor de databaseclass.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class UserDAO extends ObjectDAO {

    public $oVO;
    public $table;
    public $primarykey;

    public function __construct($id=false)
    {
        $this->table = 'user';
        $this->primarykey = 'user_id';
        $this->oVO = 'UserVO';

        if($id) {
            //$this->database_info['ID']    = $id;
            //$this->__init($this->database_info['ID']);
            $this->__init();
        }
        
    }


}






class ObjectDAO extends cDbInterface {

    public $a_oRetArr = array();
    

    public function __init()
    {
        if($this->_connection == ""){

            parent::cDbInterface();

        }
        

    }
    
    public function getByID($iID, $sFilter = NULL) 
    {
        
        $sSql = "select * from {$this->table} where {$this->primarykey} = '".$iID."' ";
        
        $aResult = $this->doQueryResult($sSql,MYSQL_ASSOC);
                
        //$classname = get_class($this->oVO);
        $classname = $this->oVO;
        $VO = new UserVO();
        
        $this->getFromResult(&$VO,$aResult[0]); 
        
        return $VO;

    }

    private function getFromResult(&$VO, $aResult) 
    {
        foreach ($aResult as $key =>$value){
            $VO->original_values[$key] = $value;
        }
    }

}


Toch heb ik het gevoel dat ik nu dingen door elkaar aan het halen ben. Of zit ik op de juiste weg?

Bovendien wordt de constructor van de extended class niet aangeroepen maar ik kan nergens terugvinden of dat daadwerklijk correct is!

Tips zijn erg welkom!

Acties:
  • 0 Henk 'm!

Verwijderd

Mag ik vragen waarom je je database velden statisch wilt houden? (en waarom je niet gevestigde paketten gebruikt ie: zend of doctrine?)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
@j.ostie: Ik ben vooral lerende... en vanuit dat oogpunt wil ik niet instappen op een kant en klare oplossing. Ik vind graag het wiel 10x opnieuw uit om er dan achter te komen dat ze vierkant zijn en er hele mooie ronde wilen op de markt zijn. 8)7 Voordeel is wel dat ik er in ieder geval iets van heb opgestoken!

Ik heb nu een beetje het idee dat ik zo half O/R-mappertje aan het mixen ben met een VO/DAO-oplossing... vandaar dat alle tips welkom zijn!

Ik wil in de VO mijn velden vastleggen omdat ik er eventueel extra info aan kan koppelen. Bijv. dat straks een van mijn velden een e-mail veld is, en bij invoer dus ook gechecked moet worden op een e-mail format.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Persoonlijk vind ik je VO's veel te ingewikkeld. Een VO hoort enkel properties te hebben, niet logica en ze moeten eigenlijk al helemaal niet afhankelijk zijn van de database.

Ik zou je toch aanraden om gewoon de generatie tools te gebruiken. Als je er perse wat van wilt leren, schrijf dan zelf een generator.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

*kucht* O-) en wijst naar zn' sig.

Mijn voornaamste tip: Probeer niet *alles* voor *elke* situatie te willen doen (waardoor je eigenlijk een soort van OO SQL krijgt. Ik heb m'n dbObject zo geschreven dat je bijv. ook heel makkelijk een custom where clause kan toevoegen aan de search/find functie in plaats van alleen $property heeft $value.

Ook is het makkelijk (maar triviaal om over het hoofd te zien) om na te denken over hoe je straks met je ORM wil gaan werken. Je kunt allerlei supermooie features bedenken, maar als je die straks uitprogrammeert en op heel moeilijke manieren allerlei references moet meegeven naar objecten die je niet zo 1,2,3, bij de hand hebt wordt het plezier van het gebruiken ervan snel de grond in geboord. K.I.S.S dus.

Bij mij werkt het zoeken van een array van objecten bijv. zo:

PHP:
1
2
3
4
5
6
 $input = dbObject::Search('ToekomstigeExVriendin', array('Gender'=>'Female', 'name like %marie%'), array('order by name'));

if($input)
{
 // results! doe dr wat mee.
}



Verder wens ik je succes met het in je kop krijgen van hoe je nou het beste je relaties kan analyseren ;)
Ik zou zeggen, download m'n dbObject even en kijk het door, je krijgt er vast wat ideeën van, en als je suggesties hebt hoor ik het ook altijd graag ;)

[ Voor 148% gewijzigd door SchizoDuckie op 06-06-2008 00:12 ]

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • wackmaniac
  • Registratie: Februari 2004
  • Laatst online: 19-09 18:02
Correct me if I'm wrong, maar is het sterke punt van ORM niet dat je niet afhankelijk bent van het gebruikte DBMS, omdat je geen SQL oid hoeft te schrijven? Als je handmatig where-clausules en order by gaat invoegen is dan het hele idee van een ORM niet een beetje teniet gedaan?

Read the code, write the code, be the code!


Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

wackmaniac schreef op vrijdag 06 juni 2008 @ 10:16:
Correct me if I'm wrong, maar is het sterke punt van ORM niet dat je niet afhankelijk bent van het gebruikte DBMS, omdat je geen SQL oid hoeft te schrijven? Als je handmatig where-clausules en order by gaat invoegen is dan het hele idee van een ORM niet een beetje teniet gedaan?
Tsja, dat is imo een keuze die je moet maken. Wil je alles weg-abstraheren of ga je er vanuit dat je toch meestal met sql99 compliant rdbms'en werkt die best wel een standaard where clause en order by snappen. Ik vond het iig vanuit zowel performance als practisch overzicht totaal overbodig om dit er bij te programmeren.
Momenteel spuugt dat ding van mij gewoon queries uit, en die werken voor zover ik weet netjes op php en sqlite (wat ik in 99.99% van de gevallen gebruik) en als je nog speciale meuk wilt hebben als odbc, oracle, firebird of mssql koppelingen is het een kwestie van de dbconnection class aanpassen met de juiste functies. Voor die 0.01% ga ik geen standaard functionaliteit inbakken wat alleen maar weer overhead oplevert of het gemak van het programmeren verkleint.

[ Voor 24% gewijzigd door SchizoDuckie op 06-06-2008 12:01 ]

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

DAO staat voor data access object, niet database access object. Eigenlijk wil je in de signatuur van de dao helemaal niks meer terug zien van SQL..De code waarin de dao wordt aangeroepen moet het helemaal niet uitmaken of het uit de database, uit een xml bestand, uit een flatfile of via een webservice binnenkomt. Dat is juist het hele idee van het scheiden van de verantwoordelijkheden.

Dat klinkt ingewikkeld, maar is het niet. Als je bijvoorbeeld je search methode bekijkt dan zou het al genoeg zijn door niet een order by letterlijk in die array te zetten, maar gewoon een array mee te geven met kolomnamen waarop gesorteerd zou moeten worden.

Verder moet een DAO niet verward worden met een ORM. De DAO is puur de interface waarlangs de ORM zijn gegevens ophoest.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
@Janoz : Dat laatste probeer ik te begrijpen maar het kwartje valt toch niet helemaal.

Voor mijn beleving:
VO is een leeg object met alle mogelijke object variabelen en de benodigde getters en setters;
DAO is een data access layer die de VO voorziet van inhoud met de standaard getItemByID, getAll, etc ?
Vanuit de DAO wordt vervolgens de database-class aangeroepen?

Maar op welke manier communiceert de DAO dan met de database indien je niets van je SQL in DAO mag terugzien? hoe weet je dan om welke tabel het gaat, wat je primary key is en wat je resultaten van de database class zijn?
En daarnaast, op welk punt ga je dan je data-validatie doen? Het liefst zo laat mogelijk, dus bij insert van de dbase. Maar hoe weet de database/code dan waarop je moet valideren?
Dat zijn echt een paar punten die me niet duidelijk zijn. Heb je misschien een voorbeeldje waardoor het wat helderder wordt?

@Schizo: Ik had stiekem al wel eens gekeken naar je sig ;)
In mijn ogen is het wel een heldere structuur! Ik zal er nog eens dieper naar kijken.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Een VO kun je eigenlijk vergelijken met een database record. Alle velden die in je database staan heb je ook als property in je VO. Daarnaast kun je geaggregeerde en berekende velden ook in je VO opnemen (die velden die je normaal gesproken juist absoluut niet in je database stopt omdat deze redundant zijn). Verder hoef je foreign keys niet als ID op te nemen, maar kun je daar gewoon het/een lijst van bijbehorende VO object(en) aan toekennen.


Je wilt in de interface van de DAO geen sql gerelateerde dingen terug zien. In de implementatie kan dat wel. Ik heb het ook over de signatuur, niet over de hele DAO.

In een DAO verwacht ik methoden als:

getNewsMessages($start, $end);

en niet

getNews("limit ".$start.",".$end - start);

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
@janoz: thanks so far, maar er blijft me toch nog wat onduidelijk in jouw voorbeeld.
VO, is helemaal helder... die berekende velden worden volgens mij gevuld vanuit de business logic toch?

In jouw voorbeeld hanteer je:

getNewsMessages($start, $end);

Ik neem aan dat je bedoelt dat daar vervolgens een resultset als return komt?
maar hoe communiceert dit vervolgens met de database? hoe kom je op de juiste query als dit niet in de DAO mag maar de dbase class mag ook weer geen link hebben met de DAO?

In het voorbeeld van schizoduckie wordt nl. deze query opgebouwd in de DAO.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Misschien wordt het duidelijker wanneer ik een simpele implementatie laat zien van die methode (compleet uit de losse pols en alle sanity checks ook ff achterwegen gelaten):

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getNewsMessages($start, $end) {
  $result = Array();
  $resultSet = mysql_query(
      "SELECT ".
      "titel, inhoud, to_unixtime(pubdatum) as datum ".
      "FROM nieuws ".
      "LIMIT ".$start.",".$eind-$start. 
      "ORDER BY DATUM");
  while ($row = mysql_fetch_array($resultSet) {
    $newsitem = new newsitem();
    $newsitem->titel = $row['titel'];
    $newsitem->inhoud = $row['inhoud'];
    $newsitem->datum = $row['datum'];
    $results[] = $newsitem;
  }
  return $results;
}



Zoals je ziet mag je in je DAO best allemaal database meuk gebruiken, alleen is dat maar 1 kant op. De aanroeper van de DAO moet niet afhankelijk zijn van de manier waarop de DAO geimplementeerd is. Een DAO levert dus ook geen resultset op, maar een lijst met VO's of een enkele VO.
die berekende velden worden volgens mij gevuld vanuit de business logic toch?
Mwah, niet helemaal. Wat ik meer bedoel is dat het een 'not done' is om in een forum tabel bij een onderwerp ook op te slaan hoeveel reacties er zijn, maar dat dat bepaald wordt door een sum op de berichten te doen. Wil je het veld toch toevoegen dan zul je daarvoor eerst een heel goede reden moeten verzinnen (bewezen performance issues bv).

In een VO is het geen enkel probleem. Daar kun je rustig een veld met aantal berichten opnemen die je vult middels een sum kolom.

[ Voor 45% gewijzigd door Janoz op 08-06-2008 18:55 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik ben ondertussen weer wat verder gaan stoeien en ik heb het idee dat ik mijn structuur wel enigszins verbeterd heb.

Toch blijft er voor mij nog een onduidelijkheid met betrekking tot de relatie tussen DAO en een databasebase class. Ik probeer dat te illustreren adhv volgende voorbeeld:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Page_DAO {

 // constructor en vanalles achterwege gelaten

    function getById($id) {
        #execute select statement
        try {
            $mysql = new PDO('mysql:host=localhost;dbname=*****', '****', '****');
            
            $sql = $mysql->prepare('select * from pages where id=?');
            $sql->bindParam( 1 , $id );
            $sql->execute();
            
            $result = $sql->fetch( PDO::FETCH_OBJ ) ;
        
        }
        catch( PDOException $e )
        {
            die( $e->getMessage() );
        }
                
        #create new vo and call getFromResult
        $vo = new Page();
        $this->getFromResult($vo, $result);

        #return vo
        return $vo;
    }
}


Echter op het moment dat ik een nieuwe class Fiets_DAO maak, is die nagenoeg identiek aan aan bovenstaande class bevalve die ene query die dan wordt:

PHP:
1
$sql = $mysql->prepare('select * from fiets where id=?');


De gehele database-afhandeling zit in deze dus in de DAO. Dat is niet wenselijk...
Het lijkt me dan zinvoller om je DAO te extenden met een db-class en vanuit je DAO niet veel meer te geven dan:

PHP:
1
      $this->db->getRecord($table,$column,$value,$order);


waarna de db-class de meegegeven variabelen gebruikt in de query:

PHP:
1
2
3
function getRecord($table,$column,$value,$order) {
      $query = 'select * from '.$table.' where '.$column.' = '.$value.' '.$order;
}


Dat is leuk met de standaard select queries.
Maar ik heb toch vaker ook uitgebreide queries die je niet als standaard kan vangen in een dbclass.

Wat is in deze best practice?
Of zit ik hiermee op het verkeerde spoor?

Daarop aanhakend.. geeft de databaseclass een (lijst van ) object(en) terug of gewoon een resultset welke ik vervolgens in mijn DAO omzet naar objecten die ik weer doorstuur naar mijn VO?... dduuh beter lezen quib.

Dit geef je al aan in je voorbeeld, je krijgt dus een resultset terug welke je vervolgens omzet naar een object.

[ Voor 14% gewijzigd door Verwijderd op 30-07-2008 12:36 ]

Pagina: 1