Welk design pattern voor database calls?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Erwin H

Erwin H

11/04/2012 12:16:43
Quote Anchor link
Vraagje voor de design pattern gurus...

Ik ben met een (re)design bezig voor een website en probeer dit te doen aan de hand van design patterns (OOP dus).

Probleem:
Hoe kan ik op een overzichtelijke en onderhoudbare manier mijn database aanspreken zonder dat er teveel onderlinge afhankelijkheden komen.

context:
De website heeft een groot aantal tabellen in de DB en over de hele site genomen worden er honderden verschillende queries op los gelaten. Er zijn verschillende groepen gebruikers waarbij niet alle gebruikers dezelfde rechten hebben en er dus moet worden gecontroleerd wie wat wil doen en of die dat mag.

Mijn (voorlopige) oplossing:
Bottom up, ik heb een database object en een connectie object die respectievelijk de daadwerkelijke database calls doet en de connectie onderhoudt. Daarbovenop heb ik een set aan objecten die de queries aanmaakt en via het database object met prepared statements en parameters de queries uitvoert. Deze objecten zijn overigens geen subs van het database object.
Omdat er voor verschillende pagina's meerdere calls achter elkaar moeten worden uitgevoerd heb ik een facade object ertussen dat de calls bundelt. Daarvoor staat dan weer een proxy die via een whitelist de calls naar de facade doorstuurt, of een error melding geeft.
De facade en proxy worden aangemaakt in een factory die weer wordt aangestuurd vanuit een controller.
En als laatste, de parameters die nodig zijn voor het uitvoeren van de queries (bijvoorbeeld zoektermen) bundel ik in een parameter klasse zodat ik niet de hele string aan calls hoef te veranderen als ik een parameter wil toevoegen in een al bestaande query. Een parameter object wordt meegegeven door de hele keten.

Nu het probleem....

Het idee is dat als ik iets wijzig of toevoeg ik zo min mogelijk aan de al bestaande objecten hoef te veranderen. Alleen dit werkt niet helemaal in mijn ogen. Als ik namelijk een query toevoeg in een van de query objecten, dan moet ik die dus aanpassen, daarna de facade (wellicht meerdere), de proxy objecten (in elk geval de proxies die de call moeten doorgeven, ik zit nu op zeker 3 proxies, worden er mogelijk 6 tot 10) en de controller, want die moet de call in gang zetten.
Dit zijn in mijn ogen teveel wijzigingen, teveel afhankelijkheden. Iemand een idee hoe ik dit model zou kunnen aanpassen om dit te verminderen? Misschien een heel ander model kiezen? Een ander design pattern?
Gewijzigd op 11/04/2012 12:24:08 door Erwin H
 
PHP hulp

PHP hulp

23/04/2024 09:49:24
 
John Berg

John Berg

28/08/2012 08:58:30
Quote Anchor link
Weliswaar een oud topic maar nog geen reactie ;-)

Ik implementeer in mijn framework zowel ActiveRecord alsook een ORM Datamapper.

Als ik even de ActiveRecord implementatie als voorbeeld neem (die is het eenvoudigste) dan zitten daar zaken in als
- FindById
- FindAll
- FindBySql
- Save (geen UPDATE of INSERT)
- Count
- Delete

In de constructor van het ActiveRecord geef ik o.a. het type database mee.

Zodra er een methode gebruikt wordt, wordt d.m.v. lazy loading een adapter gemaakt. De adapter stamt af van PDO, en kan d.m.v. chaining een SQL 'bouwen'. Momenteel heb ik adapters voor SQLite en MySQL, welke de gemeenschappelijke code hebben in een PDO_Adater class.

Nieuwe adapters bijmaken, voor b.v. Mongo is vrij eenvoudig, zonder dat ik daarvoor de ActiveRecord implementatie hoef te veranderen.

Voor ORM geld ongeveer hetzelfde, alleen daar zit het 'spul' in de Mapper.

De FindAll methode in ActiveRecord ziet er dan zo uit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
public function FindAll()
  {

    if( !$this->adapter )
      $this->adapter = $this->CreateAdapter();
    
    return $this->adapter
            ->Select( $this->tablename )
            ->
Where ( $this->conditions )
            ->
Order ( $this->sorting )
            ->
Limit ( $this->offset, $this->limit )
            ->
Execute();
  }

  ?>


En de Select in de Adapter zo:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
  public function Select( $table, array $fields = array(), $fetchall = true )
  {

    if( $fetchall )
      $this->fetch = function( $sth )  { return $sth->fetchall( \PDO::FETCH_ASSOC ); };
    else
      $this->fetch = function( $sth )  { return $sth->fetch( \PDO::FETCH_ASSOC ); };
      
    $this->sql = array();
    $this->bindings = array();
    
    if( $fields )
      $this->sql['select'] = "SELECT " . explode( ' ', $fields ) . " FROM `$table`";      
    else
      $this->sql['select'] = "SELECT * FROM `$table`";
    
    return $this;
  }

?>

Dus als designpatterns het ActiveRecord pattern i.c.m. het adapter pattern.

Voordelen: Eenvoudig, goede scheiding van 'concerns', onderhoudbaar, zowel ActiveRecord als ORM datamapper implementatie en flitsend snel.

De ORM datamapper gebruikt dezelfde adapters als de ActiveRecord implementatie.

my 2 cents, niet erg op z'n `Martin Fowlers' uitgelegd, maar het zal de bedoeling duidelijk maken.
Gewijzigd op 28/08/2012 09:05:36 door John Berg
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.