[HELP] Klassen vullen met gegevens uit database

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Yvo Lionheart

Yvo Lionheart

30/08/2015 15:19:23
Quote Anchor link
In mijn voorbeeld heb ik een tweetal klassen aangemaakt. Deze klassen representeren respectievelijk {Author} en {BlogPost}.
Nou begrijp ik hoe ik informatie uit deze klas moet ophalen of nieuwe gegevens naar deze klas kan toeschrijven, maar mij is niet duidelijk hoe dit werkt i.c.m. een database.

Is het de bedoeling dat de properties de gegevens ophalen via een database klas? Het is mij namelijk niet duidelijk hoe ik deze klas kan vullen met gegevens uit de database. De database connectie is gelukt. Het gaat dus puur over de manier waarop ik de klas kan vullen met gegevens uit de database.

Quote:
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
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
<?php

class Author{

    private $naam;
    private $biografie;
    private $avatar;

    public function getNaam() {
        print($this->naam);
    }


    public function getBiografie() {
        print($this->biografie);
    }


    public function getAvatar() {
        print($this->avatar);
    }


    public function setNaam($naam) {
        $this->naam = $naam;
    }


    public function setBiografie($biografie) {
        $this->biografie = $biografie;
    }


    public function setAvatar($avatar) {
        $this->avatar = $avatar;
    }
    
}


class BlogPost{

    private $titel;
    private $content;
    private $author;

    public function __construct() {
        $this->author = new Author;
    }


    public function getTitel() {
        print($this->titel);
    }


    public function getContent() {
        print($this->content);
    }


    public function getAuthor() {
        print($this->author->getNaam());
    }


    public function setTitel($titel) {
        $this->titel = $titel;
    }


    public function setContent($content) {
        $this->content = $content;
    }

}


?>
 
PHP hulp

PHP hulp

24/04/2024 01:26:27
 
Thomas van den Heuvel

Thomas van den Heuvel

30/08/2015 15:54:06
Quote Anchor link
Als je objecten van klassen wilt gebruiken om database-tabel-data te "mappen" in zo'n object, zou je eens kunnen kijken naar de PDO::FETCH_CLASS en PDO::FETCH_INTO methoden.

Oftewel, kijk eens naar PDO.

Daarbij kan het ook handig zijn als je er even bijvertelt over wat voor database het gaat, en hoe de structuur van de betrokken tabellen is.

Een alternatief voor bovenstaande methode is dat je je data eerst ophaalt uit je database en vervolgens meegeeft als parameter(s) aan de constructor van het klasse-object. Maar dat komt in principe op hetzelfde neer als wat je met PDO doet.

Er zijn eigenlijk legio manieren om hier invulling aan te geven. Maak je gebruik van een bepaalde ontwikkelstijl? MVC? Iets anders? Maak je gebruik van een Database Abstractie Laag? De twee bovenstaande manieren lijken mij de meest rechtstreekse manier, maar afhankelijk van welke architectuur je verder in je code gebruikt is er wellicht een andere aanpak nodig, maar dat kan ik dus niet afleiden uit je bovenstaande codefragmenten...
 
Yvo Lionheart

Yvo Lionheart

30/08/2015 16:05:40
Quote Anchor link
Thomas van den Heuvel op 30/08/2015 15:54:06:
...


Dankjewel Thomas. Jouw informatie verschaft een hoop duidelijkheid, waardoor ik de vraag wellicht beter kan verwoorden. Ben nu voor het eerst bezig met OOP programmeren in PHP (althans dat probeer ik). Dat er verschillende manieren zijn om tot een - en dezelfde - oplossing te komen, weet ik, maar ik vraag me af welke het (meest) gepast is.
Het klinkt waarschijnlijk heel stom, maar ik weet niet precies welke architectuur ik toe pas. Ik probeer de klassen met functies te scheiden van de database-klassen.

Heb in de tussentijd zelf het e.e.a. geprobeerd en ben tot het onderstaande voorbeeld gekomen. Wellicht kun je hier commentaar overgeven? Is het goed? En wat kan eventueel beter?

Quote:
private $naam;
private $biografie;
private $avatar;

public function __construct() {
$this->naam = Database::getNaam();
$this->biografie = Database::getBiografie();
$this->avatar = Database::getAvatar();
}


In de database-klas voer ik vervolgens in deze functies - middels PDO - de daadwerkelijke verbinding met de database. In de methode getNaam() binnen de database-klas wordt dus de naam geselecteerd uit de database.
 
Johan K

Johan K

30/08/2015 16:36:54
Quote Anchor link
Je zou eigenlijk in de constructor van "Author" de database handle moeten zetten, en vanuit daar de database query gaan uitvoeren.

Je database classe zou eigenlijk alleen functies moeten bevatten die puur met de database te maken hebben, en niet zo zeer met de structuur in jouw database.
Jouw author classe, zou dus eigenlijk dit moeten overnemen omdat je dan weet waar ongeveer de code staat.

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
20
21
<?php
function __construct($id = 0){
  $db = Database::getInstance();
  $stmt = $db->prepare('select * from table where id = ?');
  // etc, bind values, etc, etc.

  try{
    if(($result = $stmt->execute($id)) != false){
     $row = $stmt->fetch(PDO::FETCH_ASSOC);
     $this->naam = $row['naam'];
     //etc.
    } catch (Exception $e){
      echo $e->getMessage();
    }
  }
}
?>


<?php
$author
= new Author(1);
echo $author->getNaam(); // <-- really, nederlands and english door eachother?
?>


Maar het is net hoe je het wilt gebruiken, in dit geval ga ik er vanuit dat je maar 1 auteur wilt uitprinten maar als je een complete lijst wilt uitprinten zal het efficiënter zijn om 1 grote query (select naam, etc, etc from auteur LIMIT = 10) en dan een array van Author maken, of dit binnen de classe laten verwerken.
Gewijzigd op 30/08/2015 16:45:26 door Johan K
 
Yvo Lionheart

Yvo Lionheart

30/08/2015 16:39:42
Quote Anchor link
Johan K op 30/08/2015 16:36:54:
..


Excuses voor het door elkaar gebruiken van Nederlands en Engels. Het is ietwat snel in elkaar geflanst. Heb het even omgezet naar English-only.
Zou je je code iets meer willen toelichten?
Gewijzigd op 30/08/2015 16:40:26 door Yvo Lionheart
 
Thomas van den Heuvel

Thomas van den Heuvel

30/08/2015 16:47:04
Quote Anchor link
Ik neem aan dat je ook een soort van identificerend attribuut hebt? Een user id (meestal vertegenwoordigd door het auto-increment veld van de bijbehorden tabel)? Daarmee zou je alle informatie in 1x kunnen ophalen.

Verder hangt hoe je klasses er uitzien af van hoe je deze gebruikt, ik weet niet of je altijd alle informatie in een object hoeft te stoppen als je hier op elk moment maar een klein deel van gebruikt. Ook zou je slim gebruik kunnen maken van reeds aanwezige / geladen informatie. Die avatar bijvoorbeeld, is dat de naam van een afbeelding? Wat nu als je zo'n afbeelding altijd converteert naar JPG of PNG bij uploaden, en vervolgens hernoemt naar het user id? Je zou dan nog wel kunnen bijhouden of iemand een afbeelding heeft geupload (hasAvatar), maar de naam zelf ligt al vast door andere data.

Dat je de communicatie met je database via objecten wilt laten verlopen is in principe al een ontwerpbeslissing, je zult ook moeten kunnen onderbouwen waarom je voor deze opzet kiest. Ik zou het in eerste instantie wat simpeler houden denk ik. Wat je ook zou kunnen doen is een referentie van je database door kunnen geven aan je klasses, en daar dan gewoon queries kunnen uitvoeren. Of je maakt het meteen een stuk abstracter en gaat echt werken met een ORM systeem.
 
Yvo Lionheart

Yvo Lionheart

30/08/2015 16:59:58
Quote Anchor link
Thomas van den Heuvel op 30/08/2015 16:47:04:
Ik neem aan dat je ook een soort van identificerend attribuut hebt? Een user id (meestal vertegenwoordigd door het auto-increment veld van de bijbehorden tabel)? Daarmee zou je alle informatie in 1x kunnen ophalen.

Verder hangt hoe je klasses er uitzien af van hoe je deze gebruikt, ik weet niet of je altijd alle informatie in een object hoeft te stoppen als je hier op elk moment maar een klein deel van gebruikt. Ook zou je slim gebruik kunnen maken van reeds aanwezige / geladen informatie. Die avatar bijvoorbeeld, is dat de naam van een afbeelding? Wat nu als je zo'n afbeelding altijd converteert naar JPG of PNG bij uploaden, en vervolgens hernoemt naar het user id? Je zou dan nog wel kunnen bijhouden of iemand een afbeelding heeft geupload (hasAvatar), maar de naam zelf ligt al vast door andere data.

Dat je de communicatie met je database via objecten wilt laten verlopen is in principe al een ontwerpbeslissing, je zult ook moeten kunnen onderbouwen waarom je voor deze opzet kiest. Ik zou het in eerste instantie wat simpeler houden denk ik. Wat je ook zou kunnen doen is een referentie van je database door kunnen geven aan je klasses, en daar dan gewoon queries kunnen uitvoeren. Of je maakt het meteen een stuk abstracter en gaat echt werken met een ORM systeem.


Zou je de vetgedrukte zin voor mij kunnen toelichten m.b.v. een klein codefragment? Wellicht dat het inderdaad verstandig is om het in het beginsel iets simpeler te houden.
Wat betreft het slim gebruik maken van aanwezige informatie; super tip! Dank je wel :-).
 
Johan K

Johan K

30/08/2015 17:06:59
Quote Anchor link
Yvo Lionheart op 30/08/2015 16:59:58:
Zou je de vetgedrukte zin voor mij kunnen toelichten m.b.v. een klein codefragment? Wellicht dat het inderdaad verstandig is om het in het beginsel iets simpeler te houden.
Wat betreft het slim gebruik maken van aanwezige informatie; super tip! Dank je wel :-).

Dat is bijna het zelfde in mijn voorbeeld;

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
20
21
22
23
24
25
26
27
28
29
30
31
<?php
$db
= new Database($user, $pass, $dsn);

class foo{
  static $instance;
  
  static function getInstance(...$args){
    return isset(self::$instance) ? self::$instance : new foo(...$args);
  }

  function
__construct($db){
    self::$instance = $this;
    $db->query(/*etc*/);
  }
}


class author{
  private $db;

  function
__construct(){
    $this->db = foo::getInstance();    
  }
}


$a = new foo($db);
$b = foo::getInstance($db);
$c = foo::getInstance();

echo $a === $b && $a === $c ? 'true' : 'false';

?>


Alleen in mijn voorbeeld ga ik er vanuit dat jouw "database" classe een statische methode heeft van "getInstance()" zoals in classe foo zodat deze niet in de argumenten hoeft te staan.
Gewijzigd op 30/08/2015 17:12:42 door Johan K
 
Frank Nietbelangrijk

Frank Nietbelangrijk

30/08/2015 21:55:11
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$this
->naam = Database::getNaam();
$this->biografie = Database::getBiografie();
$this->avatar = Database::getAvatar();
?>


Zoals je zelf al zult aanvoelen is dit niet handig. De class Database kan zo wel heel erg groot gaan worden met allerlei functienamen die uiteindelijk hetzelfde doen.

Het voorbeeld uit je eerste post doet sterk denken aan een entity van Doctrine ORM. Een entity heeft alle data uit 1 record van een database-tabel. Deze constructie bouw je niet zo even na en het gaat veel te ver om je hierin te verdiepen als je OOP wilt leren. (overigens is Doctrine erg favoriet en wordt het bijvoorbeeld in het Symfony framework gebruikt en je kunt het ook in je eigen gebouwde framework gebruiken).

Ik zou starten met MVC. Het wordt te veel om hier heel uitgebreid over te vertellen maar er is voldoende info te vinden over dit design pattern. Een typisch lichtgewicht MVC framework is Codeigniter. Als je hier voor de gein eens mee aan de slag gaat dan wordt het MVC principe snel helder.


Toevoeging op 30/08/2015 21:58:46:

Ik zou Codeigniter niet willen aanraden voor het 'echte' werk overigens. Hiervoor blijven Symfony (mijn favoriet) en Laravel aan de top.

Toevoeging op 30/08/2015 22:12:38:

Toch maar even een voorbeeld ala codeigniter om je uiteindelijke vraag te beantwoorden

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
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php

// basis class
class Model
{
    function
__construct() {
        // hier maak je je verbinding met de database
    }

    protected function query($query)
    {

        // voer een query uit en return het resultaat
    }
}


// afgeleide class van Model
class AuthorModel extends Model
{
    public function getAllAuthors() {
        return $this->query('SELECT * FROM authors');
    }
}


$model = new AuthorModel();
$authors = $model->getAllAuthors();

foreach($authors as $author)
{

    echo $author['name'] . '<br>';
}


?>
Gewijzigd op 30/08/2015 22:13:51 door Frank Nietbelangrijk
 



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.