SQL en OOP

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Jens V

Jens V

09/01/2011 20:43:07
Quote Anchor link
Goede avond allen,

Ik ben om te leren OOP te programmeren met php een forum aan het maken.

Wat is nu de beste methode om je objecten te vullen met de data uit de database? Moet je een constructor (of aparte functie) maken met daarin de SQL om je hele object te van zijn data te voorzien door bijvoorbeeld een id mee te geven? Of is het de bedoeling dat je buiten het object een query uitvoert en d.m.v. je setters de data in je object pompt?

Na lang denken en wikken en wegen ben ik hier nog steeds uit.

Groeten,
Jens V
 
PHP hulp

PHP hulp

21/11/2024 15:16:28
 
Noppes Homeland

Noppes Homeland

09/01/2011 20:52:07
Quote Anchor link
indien je sql in een class opneemt dan ben je dus afhankelijk van .... en dat is nu net niet de bedoeling.
 
Jens V

Jens V

09/01/2011 21:22:34
Quote Anchor link
Voorbeeldje van hoe het wel moet?

Ik ben gewend programma's te schrijven in C++ en Java, en dat allemaal OOP. Het voordeel daar is dat je objecten over het hele programma blijven bestaan, tenzij je de destruct. Hoe moet je dat oplossen in php?

Jens
 
Pim -

Pim -

09/01/2011 21:23:26
Quote Anchor link
De mooiste manier is een ORM. Dat kan op twee manieren (voor zover ik weet)
- Active record. Je Domain Object (User) extend een bepaalde klasse. Je vindt dit oa in Doctrine 1.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
$user
= User::find($id);
$user->setEmail('bla');

$group = Group::find($id);
$user->setGroup($group);

$user->save();
?>

Dit heeft het nadeel dat je Domain Objects afhankelijk worden van je Active Record mechanisme. Mooier is methode twee:
- Data mapper. Een andere klasse regelt de 'persistence' (opslag) van je objecten. Je vindt oa in Doctrine 2. De andere klasse heet daar de Entity Manager.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?
$user
= $em->find('User', $id);
$user->setEmail('bla');

$group = $em->find('Group', $id);
$user->setGroup($group);

$em->persist($user); // Stel het object in als 'persistent'
$em->flush(); // Doe alle wijzigingen in 1x
?>


Handmatig kan natuurlijk ook:
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
<?php
class ActiveRecord
{
    protected static $db; // Kan ook als array

    public static function setDb(PDO $db, $identifier = 'default');
    public static function getDb($identifier = 'default');
}


class User extends ActiveRecord
{
    public static find($id);

    public function save();
}

?>

Maar dit kost veel werk en associaties zijn lastig beheersbaar.
Gewijzigd op 09/01/2011 21:33:15 door Pim -
 
Jens V

Jens V

09/01/2011 21:34:04
Quote Anchor link
@Pim, hier ben ik precies toch nog niet echt mee weg. Zo een Entity Manager, wat doet dat precies? Kan je eens een voorbeeldje geven?

Wat me ook nog steeds niet duidelijk is, is de algemene structuur van een opgeroepen pagina. Stel, ik roep de pagina op die gewoon het overzicht van forums ('categorien') laat zien. Hoe ziet dat er dan uit?

Ik heb als 'model' gewoon een paar klassen die Forum, Topic en Post voorstellen. Maar deze klassen hebben tot nu toe nog geen enkele functionaliteit. Ik neem aan dat iets zoals het volgende niet de bedoeling is?
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
<?php
$sql
= "SELECT * FROM forums ORDER BY title ASC";
// uitvoeren
$forums = array();
foreach($result as $forum)
{

    $forums[] = new Forum(/* data in $forum hierin stoppen */);
}

// html bla bla bla
for($i = 0; $i < count($forums); $i++)
{

    $f = $forums[$i];
    // uitschrijven dmv $f->getTitle(); etc
}
?>


Dat lijkt mij eigenlijk gewoon dubbel werk...

Hoe dus wel? :)
Gewijzigd op 09/01/2011 21:35:01 door Jens V
 
Mark PHP

Mark PHP

09/01/2011 22:54:16
Quote Anchor link
Elders op dit forum heb ik al kenbaar gemaakt dat ik op zijn zachtst gezegd geen fan ben van Active Record. Zelf gebruik ik vaak het Data Mapper pattern. En ja, die schrijf ik allemaal handmatig.

De beste manier om objecten te vullen vanuit een query vindt ik dan ook:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
PDOStatement::fetchAll(PDO::FETCH_CLASS, 'MyClass', array('argv'));
?>

Met __set() kan je dan nog eventueel gedrag beïnvloeden.
Gewijzigd op 09/01/2011 22:58:36 door Mark PHP
 
Kris Peeters

Kris Peeters

10/01/2011 10:23:55
Quote Anchor link
Wat ik, over het algemeen, vind wanneer men vraagt naar de zinnigheid van OOP en hoe men het moet aanpassen...

Bekijk het eens van de andere kant.
Vergeet even de class op zich en denk aan het gebruik er van, buiten de class.

Schrijf je logica en doe alsof de methodes van je class al precies doen wat je wil.
Als je dat hebt, vul dan je class in en zorg dat het doet wat je vraagt.

Een voorbeeld: een gastenboek:
Wat is dat? Een formulier, een lijst berichten en de mogelijkheid om een nieuw bericht te posten.
Voor mij zijn dat dus drie publieke methodes (+ een constructor uiteraard).
Je zou er zo-iets van kunnen maken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php
  require_once('guestbook.php');
  $m_guestbook = new guestbook();
  if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $m_guestbook->postMessage($_POST);
    header('location ...');
  }

  else {
    $guestbook = $m_guestbook->form() . $m_guestbook->messages();
    echo '<html>...<body>... '. $guestbook .'</body></html>';
  }

?>


Als je dit hebt, dan kan je beginnen nadenken over hoe je guestbook.php precies aanpakt.
Gewijzigd op 10/01/2011 10:25:51 door Kris Peeters
 
Jens V

Jens V

10/01/2011 10:35:46
Quote Anchor link
@Kris,

In je voorbeeldje van je guestbook, waar haal je nu je gegevens uit je db? In je guestbook-klasse neem ik aan? En waar dan?
 
Kris Peeters

Kris Peeters

10/01/2011 13:25:50
Quote Anchor link
Ik vind dat het zinnig is om twee variabelen globaal te zetten:
Een $db object en een $user object.

$db is bv. een pdo object. Eventueel gewrapped in een eigen geschreven class.

Overal waar je een query moet uitvoeren, doe je bv. dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php
  class guestbook {
  ...

  public function messages() {
    global $db;
    ...

    $res = $db->query($sql);
  }
}

?>


Zo'n $user object kan dan dingen bijhouden als ingelogd / ip / e-mail ... van de huidige client.

Mijn punt is vooral: je moet je algemene logica van je class niet omgooien omdat "men" zegt dat je beter geen query's laat uitvoeren binnen classes.
Gewijzigd op 10/01/2011 13:27:24 door Kris Peeters
 
Jens V

Jens V

10/01/2011 14:41:35
Quote Anchor link
Oké, bedankt. Het een en ander is nu wel duidelijk, denk ik. Ik kan wel eens aan de slag.

Nog iets, jij hebt functies om een heel form of de rest uit te printen? Is dat wel zo goed?

En als ik dit nu met Smarty ofzo wil doen? Kan ik dan via een assign een heel object meegeven en dat object 'ondervragen' (data uithalen) in de tpl-files?

edit:
Dat van Smarty heb ik gevonden, assign_by_ref() :)
Gewijzigd op 10/01/2011 15:50:20 door Jens V
 
Kris Peeters

Kris Peeters

10/01/2011 15:51:31
Quote Anchor link
Sorry, ik weet veel te weinig van Smarty om hier verder iets zinnigs te zeggen.
 
Niels K

Niels K

14/01/2011 21:53:03
Quote Anchor link
@Kris peters
Globals zijn uit de boze! Beter is om DI te gebruiken.

Voorbeeld:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php
public function __construct( Database $db )
{

    $this->database = $db;
}


public function message( )
{

    $sql = '...';
    $this->database->query($sql);
}

?>


Offtopic:

Het is een beetje een late reactie maar kon het niet laten om het te zeggen.
 
Jens V

Jens V

14/01/2011 21:55:41
Quote Anchor link
Toch bedankt ;) Heb ook altijd gehoord dat globals niet zo geweldig zijn, maar ja:)
 
Kris Peeters

Kris Peeters

14/01/2011 21:59:10
Quote Anchor link
Ik vind dit een perfect voorbeeld van een uitzondering waarbij een global wel nuttig is.

Nota bene, drupal doet het ook zo. Het $user object staat global (Bij databases gaat het met wrapper functies).
Gewijzigd op 14/01/2011 22:02:36 door Kris Peeters
 
Bas Cost Budde

Bas Cost Budde

14/01/2011 22:45:11
Quote Anchor link
Globals kunnen in de weg zitten wanneer je het overzicht kwijtraakt, en het aanwijsbare nadeel is dat je niet duidelijk terugvindt waar er een waarde aan wordt toegekend.

Gebruik jij 1 user-object in je applicatie (en dat ligt nogal voor de hand binnen de context van een webrequest), dan is een global volstrekt legitiem. Om te lezen wel te verstaan. Wordt er op diverse plekken in je toepassing een nieuwe user in gezet, dan klopt er weer iets niet (iets wijzigen aan het *user-object* waarnaar de global verwijst is weer hartstikke OK).
 
Pim -

Pim -

15/01/2011 13:01:53
Quote Anchor link
De Doctrine Entity Manager regelt de 'persistence' van de gekoppelde 'entities'. Alle Domain Objects (entities) die je met $em->persist($object) aan de EM koppelt, blijven behouden in de laatste staat.

Wanneer je dus een nieuw User object koppelt en het emailadres verandert (de volgorde maakt niet uit), blijft dat emailadres veranderd in de daarop volgende requests.

In de EM kan een object 2 statussen hebben (+ nog 2, die er nu niet toe doen).
- Nieuw, er wordt dus een insert uitgevoed
- Attached, een object is met de EM opgehaald en gewijzigd. De EM vergelijkt het origineel met de gewijzigde versie en updated de wijzigingen naar de DB.

Wanneer een object wordt opgehaald, gebruikt de EM reflection om de properties te vullen. Zo heb je minder getters/setters nodig en kan je de constructor gebruiken voor het maken van nieuwe objecten.

Hoe een object in de DB weergegeven moet worden, stel je in in ofwel phpDoc blocks, ofwel een XML of YAML bestand.

Om objecten op te halen maak je gebruik van Repositories. Hierin kan je ingewikkelde SELECT DQL (een SQL variant, maar dan nuttig voor gebruik in een ORM) queries opslaan.
 



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.