Hallo,

Ik ga met iemand anders een projectje doen waarbij we een site gaan maken.
Aangezien we met z'n tweeën gaan werken leek het me handig om eens met OOP aan de slag te gaan, aangezien we al hebben ervaren dat de spaghetti code voor ons beiden vervelend kan zijn.

Ik heb redelijk wat over OOP gelezen maar ik kom heel moeilijk aan praktijk voorbeelden.
Al te vaak lees je over een auto classe of over een hond classe, die je kunt extenden naar een poedel bijvoorbeeld.

Ik heb in ieder geval geprobeert een beginnetje maken maar ik vraag me nu al af of ik wel op de goede weg zit en niet verkeerd aan het denken ben.
Ik heb op verschillende plekken gelezen dat setter en getter 'evil' zijn en ik betrap mezelf erop er al veelvuldig gebruik van te maken.

Ik was bezig met een Gebruiker classe voor de site, simpelweg omdat ik geen idee had waar ik anders moest beginnen.
Ik zal hieronder posten wat ik tot nu toe heb gedaan en zou graag commentaar hebben op het geheel (ook de foutafhandeling bijvoorbeeld, ik heb vrij veel gebruikt van jorendewit.nl)
Zoals je kunt zien gebruik ik in de Gebruikers classe al vrij veel setter en getters, en blijkbaar is dit niet goed maar ik vraag me af hoe ik dit anders moet aanpakken.

Ik hoor graag wat jullie te vertellen hebben!

index.php

<?php

ini_set('display_errors', 'On');
error_reporting(E_ALL);


require 'includes/db_config.php';
require 'includes/error_handler.php';


function __autoload($class_name) {
require_once 'classes/' . strtolower($class_name) . '.class.php';
}



try
{
$db = new PDO('mysql:host=' . $db_host . ';dbname=' . $db_name,$db_user,$db_pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);



$user = new Gebruiker(1, $db);

if($user->get_tussenvoegsel() != NULL)
{
$tussenvoegsel = ' ' . $user->get_tussenvoegsel() . ' ';
}
else{
$tussenvoegsel = ' ';
}
// GEWOON TESTEN
echo 'Naam: ' . $user->get_voornaam() . $tussenvoegsel . $user->get_achternaam();



}

catch(PDOException $e)
{
echo 'PDOEXCEPTION';
echo '<pre>';
echo 'Regel: '.$e->getLine().'<br>';
echo 'Bestand: '.$e->getFile().'<br>';
echo 'Foutmelding: '.$e->getMessage();
echo '</pre>';

}

catch(Exception $e)
{
echo '<pre>';
echo 'Regel: '.$e->getLine().'<br>';
echo 'Bestand: '.$e->getFile().'<br>';
echo 'Foutmelding: '.$e->getMessage();
echo '</pre>';

}
?>


classes/gebruiker.class.php
(hier was ik nog mee bezig)

<?php

class Gebruiker {

private $id;
private $voornaam;
private $tussenvoegsel;
private $achternaam;
private $email;
private $rechten;
private $geslacht;
private $regip;
private $regdatetime;
private $werknemer;
private $werkgever;
private $db;

public function __construct($id, $db){

if(!is_int($id)){
throw new Exception('Aanmaken instantie van "'.__CLASS__.'" mislukt. $id is geen INT');
}

$this->set_id($id);
$this->db = $db;
}

// ID SETTER & GETTER
private function set_id($id){
// Deze moet nog verder uitgewerkt worden uiteraard
$this->id = $id;
}
public function get_id(){
// Deze moet nog verder uitgewerkt worden uiteraard
return $this->id;
}

public function set_voornaam($voornaam){

if(!is_string($voornaam)){
throw new Exception('Kon voornaam niet veranderen. Waarde is geen STRING');
}

$sql = "UPDATE tbl_gebruikers SET voornaam = :voornaam WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':voornaam', $voornaam);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

if($stmt->rowCount() == 0)
{
throw new Exception('Er zijn geen rijen gewijzigd in de UPDATE query "'. $sql . '"');
}

}
public function get_voornaam(){

$sql = "SELECT voornaam FROM tbl_gebruikers WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row['voornaam'];

}




public function set_tussenvoegsel($tussenvoegsel){

if(!is_string($tussenvoegsel)){
throw new Exception('Kon tussenvoegsel niet veranderen. Waarde is geen STRING');
}

$sql = "UPDATE tbl_gebruikers SET tussenvoegsel = :tussenvoegsel WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':tussenvoegsel', $tussenvoegsel);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

if($stmt->rowCount() == 0)
{
throw new Exception('Er zijn geen rijen gewijzigd in de UPDATE query "'. $sql . '"');
}

}

public function get_tussenvoegsel(){


$sql = "SELECT tussenvoegsel FROM tbl_gebruikers WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row['tussenvoegsel'];

}



public function set_achternaam($achternaam){

if(!is_string($achternaam)){
throw new Exception('Kon achternaam niet veranderen. Waarde is geen STRING');
}

$sql = "UPDATE tbl_gebruikers SET achternaam = :achternaam WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':achternaam', $achternaam);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

if($stmt->rowCount() == 0)
{
throw new Exception('Er zijn geen rijen gewijzigd in de UPDATE query "'. $sql . '"');
}

}

public function get_achternaam(){


$sql = "SELECT achternaam FROM tbl_gebruikers WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row['achternaam'];

}




public function set_email($email){

if(!is_string($email)){
throw new Exception('Kon email niet veranderen. Waarde is geen STRING');
}

$sql = "UPDATE tbl_gebruikers SET email = :email WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

if($stmt->rowCount() == 0)
{
throw new Exception('Er zijn geen rijen gewijzigd in de UPDATE query "'. $sql . '"');
}

}

public function get_email(){


$sql = "SELECT email FROM tbl_gebruikers WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row['email'];

}



public function set_rechten($rechten){

if(!is_int($rechten)){
throw new Exception('Kon rechten niet veranderen. Waarde is geen INT');
}

$sql = "UPDATE tbl_gebruikers SET rechten = :rechten WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':rechten', $rechten);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

if($stmt->rowCount() == 0)
{
throw new Exception('Er zijn geen rijen gewijzigd in de UPDATE query "'. $sql . '"');
}

}


public function get_rechten(){

$sql = "SELECT rechten FROM tbl_gebruikers WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':id', $this->id);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row['rechten'];

}






}
?>


includes/db_config.php

<?php

$db_host = XXX;
$db_name = XXX;
$db_user = XXX;
$db_pass = XXXX;

?>

includes/error_handler.php

<?php

function myErrorHandler($iLevel, $sMessage, $sFile, $iLine)
{
$aLevels = array(
2 => 'WARNING',
8 => 'NOTICE',
256 => 'FATAL ERROR',
512 => 'WARNING',
1024 => 'NOTICE' );

if(array_key_exists($iLevel, $aLevels))
{
$sLevel = $aLevels[$iLevel];
}
else
{
$sLevel = 'ONBEKENDE FOUT';
}

echo 'FOUT<br />';
echo '<b>Foutsoort:</b> '.$sLevel.'<br />';
echo '<b>Foutmelding:</b> '.$sMessage.'<br />';
echo '<b>Bestand:</b> '.$sFile.'<br />';
echo '<b>Regel:</b> '.$iLine.'<br />';

if($iLevel == 256)
{
echo 'Script wordt gestopt...';
exit();
}
}

set_error_handler('myErrorHandler');

// EXCEPTIONS

function myExceptionHandler($e)
{
echo 'FOUT: Er is een exception niet opgevangen.<br />';
echo 'Melding: '.$e->getMessage();
}

set_exception_handler('myExceptionHandler');

?>
Even een vraagje vanuit mijn kant; ik zie allemaal queries staan in een User klasse.. Is het niet verstandiger om dit juist uit te besteden aan een databaseklasse? Ik bedoel, een klasse User hoeft toch niets van de database te weten? En stel dat de database veranderd, moet er van alles aangepast worden in de User klasse, die eigenlijk zelf niets met de database te maken heeft?
Niek schreef op 03.01.2010 18:10
Even een vraagje vanuit mijn kant; ik zie allemaal queries staan in een User klasse.. Is het niet verstandiger om dit juist uit te besteden aan een databaseklasse? Ik bedoel, een klasse User hoeft toch niets van de database te weten? En stel dat de database veranderd, moet er van alles aangepast worden in de User klasse, die eigenlijk zelf niets met de database te maken heeft?
Dat gebeurt ook.
Er is een db class en daar maakt de user class gebruik van.
Die db class zit in de registry.
Maar je voert wel queries uit in User? Dus stel je voor dat je tabellen in je database veranderen, dan moet je in je User klas dingen gaan wijzigen..

Niet echt logisch naar mijn idee.
Niek schreef op 03.01.2010 18:52
Maar je voert wel queries uit in User? Dus stel je voor dat je tabellen in je database veranderen, dan moet je in je User klas dingen gaan wijzigen..

Niet echt logisch naar mijn idee.
Tuurlijk doe ik dat.
Als jij je datamodel gaat aanpassen moet je toch ook je queries aanpassen?
Ik vind jou een beetje onlogisch, hoe zou jij het dan doen ? :P

Maar ik zat eigenlijk te wachten op een reactie van Blanche of Jelmer :)
Ik heb hier dus eigenlijk twee classes nodig.
User en User_Controller? (en User_Validator, of die niet?)
Meer User en User_Store (Controller mag ook wel, maar dat is dan weer verwarrend met de Controller in MVC, want die laatste is net even iets anders)

Maar Niek heeft inderdaad grotendeels gelijk: In je User class heb je geen database nodig. Je User class hoeft het opslaan niet te regelen. Je User class hoeft er alleen maar voor te zorgen dat hij altijd klopt (z'n eigen data bewaken zeg maar) en dat je geen ongeldige username aan een user kan toekennen bijvoorbeeld.

De User_Store class daarentegen hoeft zich niet bezig te houden met de eisen van wat een User een User maakt. Het moet gewoon User-objecten accepteren en die invoegen of ophalen uit de database. (In praktijk moet je User_Store dus wel degelijk de opbouw van je User weten omdat zo ongeveer overeen komt met de database tabel)
Zou ik dan nog een User_Validator nodig hebben? Of moet dat in de User_Store?
Die controleert in het bovenstaande geval of de attributen geldig zijn ( die een gebruiker invult)
De User class weet toch hoe hij eruit ziet? Laat die zichzelf lekker controleren. Doet die tenminste ook nog wat nuttigs behalve data vasthouden.
Bedankt voor je hulp Jelmer.
Ik heb wel nog wat vragen :P

Een gebruiker moet zich op mijn site kunnen inloggen.
Heb ik daar dan een auth class voor nodig?
Of moet dat in de User ? Kan een user zichzelf inloggen ? (ja toch?!)
Dat is me soms niet helemaal duidelijk.

Dus ik heb bijvoorbeeld dit:
<?php
// nadat je inlogt.
$userstore = new User_Store();
$user = $userstore->getUser($id);

// USER kan dingen met zichzelf doen (in dit geval word alles gecontroleert en uitgevoerd)
$user->editProfile($profilearray);
$user->getId();

// nieuwe user maken?
$user2 = $userstore->register($registerInfo);

?>

Is het bovenstaande een beetje in de goede richting ?
Want als ik het zo bekijk hierboven voert de User class wel queries uit, namelijk zijn eigen profile info aanpassen.

Of moet dat dan zo?

<?php
// nadat je inlogt.
$userstore = new User_Store();
$user = $userstore->getUser($id);

// de user class zet in dit geval enkel data in het object, niets word weggeschreven in de database.
$user->editProfile($profilearray);
$userstore->update($user);

?>

Ik hoop dat je me verder kan helpen.
Thanks!
De onderste versie zie je vaker omdat je daarin de user, en de plek waar users worden onthouden goed kan scheiden. Voordeel daarvan is dat je er gemakkelijk een laagje tussen kan stoppen, bijvoorbeeld een laagje waar heet user-object niet rechtstreeks uit de database komt, maar uit een cache (apc ofzo) of een andere bron.

Voor het inloggen zou ik nog een andere class erbij maken. Denk aan een class waar tegen je zegt dat deze gebruiker wil inloggen, en welke je vervolgens vraagt of de gebruiker dit mag doen, en dat, en zus en zo. De rechten van de gebruiker controleren is niet een taak van de gebruiker zelf, maar van dat ding dat de rechten afdwingt. (goh, je zou hier politiek in kunnen zien. Je hebt de overheid: de class die de rechten opslaat. Je hebt de politie: de class die bijhoudt welke gebruiker is ingelogd en die je vraagt of de gebruiker dit en dat mag doen. En je hebt het volk: de gebruiker)

Reageren