Archief - php database vertalen naar class

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

wdelements

Legacy Member
Momenteel ben ik begonnen met een website volledig in oo te maken en ben ik gebotst op een kwestie waar ik niet helemaal uitgeraakt.

Stel je hebt twee tabellen:
Product en Categorie

Product heeft de velden productID, productNaam en categorieID
Categorie heeft de velden categorieID en categorie.

Nu vraag ik mij af, als ik de class Product maak, hoe handel ik dan het beste de categorie af, door de id toe te voegen aan de Product class of door het object categorie toe te voegen aan de Product class.

dus Class Product
$productID
$productNaam
$categorieID

of
Class Product
$productID
$productNaam
$categorie (dit is een categorie object)

Fraggie

Legacy Member
Heb je soms een UML-classe diagramma waarop alle associaties staan? Want met de weinige uitleg dat er nu staat lijkt het er op dat je een one-to-one vertaling doet van je db-structuur naar klassen. Een volledig UML-classe diagramma zal de zin of onzin hiervan moeten uitwijzen.

wdelements

Legacy Member
Het is eerder een algemene vraag die niet specifiek voor dit maar voor alle oo projecten bedoeld is die ik van plan ben te maken.
Maar het is in ieder geval een 1-1 relatie tussen product en categorie.
Ik vraag mij gewoon af of je in een klasse object altijd een ander object moet steken of gewoon de id.
Dus bij product de categorie ID of het volledige object, bij een user de rangID of het volledige rang object.

Fraggie

Legacy Member
Dat hangt er vanaf, kan je zeggen dat een Product een Categorie bevat? Zo ja kan je via compositie verwijzen van het de Product klasse naar de Categorie klasse.

Echter lijkt het mij niet logisch dat een Product een Categorie bevat. Beter lijkt me om de klasse Categorie te laten vallen en de code in Product te steken? Je moet je niet beperken tot de relaties die je kan leggen in de database.

wdelements

Legacy Member
Het is idd niet logisch dat Product een Categorie-object bevat.
Maar een categorieID in de productclass lijkt mij niet incorrect?
Dus zoals ik het heb gedaan:
$product = new Product("test",1) test = naam, 1 is de categorieID (de value uit een option list ofzo..)
$product->save()
...
insert into product(naam,categorieID) values($this->productNaam, $this->categorieID);

Dat lijkt mij toch correct? Zo vind ik het toch op tal van tutorials terug.

Fraggie

Legacy Member
Jou voorbeeld overtuigt mij niet dat je OOD nodig hebt, je zou het 'probleem' even goed (zelf sneller) structureel kunnen oplossen. Je schijnt de indruk te geven dat je enkel maar data wil samen zetten in een container, maar daarvoor heb je al een relationele database imo.

Tenzij je meer inzicht in de zaak kan geven?

wdelements

Legacy Member
Ik ben eerder op zoek naar een manier om gestructureerd projecten uit te werken.
heb dus als volgt een idee:

database:
tabel: product
velden: productID,productNaam en categorieID

tabel:categorie
velde: categorieID,categorie

klassen in php:

product met $productID,$productNaam en $categorieID
categorie met $categorieID, $categorie

Dataklassen in php:

DataProduct met de methods getProduct($id) en insertProduct($product)
DataCategorie met de methods getCategorie($id) en insertCategorie($categorie)

Dus aparte objecten en dataklassen om database en entiteiten mooi gescheiden te houden.
Dit omdat ik bijvoorbeeld vaak een klasse Product zie die dan ook een database object en queries bevat, wat ik liever apart houdt omdat ik dat logischer en overzichtelijker vind.

Nu kan ik dan bijvoorbeeld een nieuw product maken:


Het enige waar ik wat mee worstel is of ik in de productklasse dan de id van de categorie moet bijhouden of de volledige categorie als object.

Een vertaling van de database lijkt mij hier het beste (dus categorieID in de klasse Product) en dan via DataCategorie.getCategorie($id) het categorieObject opvragen indien ik bijvoorbeeld de naam van de categorie wil displayen bij een product.

Een nieuw product kan ik dan maken en toevoegen als volgt:
$product = new Product($naam,$catID)
DataProduct.insertProduct($product)

dJeez

Legacy Member
Je bent hier precies toch wel 2 concepten door elkaar aan het gooien. Met name het relationele model en het objectmodel. In het relationele model leg je links tussen tabellen met IDs, in het objectmodel gebruik je echter de objecten op zich, daar ga je dus in principe niet enkel een categorie-ID gebruiken, maar wel degelijk een instantie van je categorie object (maar bij het bewaren in de DB sla je uiteraard enkel de ID op, al dan niet in een linktabel).

Als je je het leven wat makkelijker wil maken, gebruik dan misschien eens een ORM tool. Bij voorkeur Propel voor PHP (Doctrine sucks :p). Daar definieer je in een XML bestand al je objecten/tabellen en wordt de basiscode om met die objecten gegenereerd op basis van die definitie. Je kan er misschien wel nog iets van leren (hoewel je - als je de gegenereerde code beijkt - ook wel zal merken dat omwille van lazy loading een ORM doorgaans zowel een ID als een verwijzing naar gelinkte objecten zal bevatten in de uitwerking van de klasse).

YaMo

Legacy Member
Het lijkt mij nogal logisch dat als je OO wilt werken, je verwijzingen gaat leggen via objecten en niet via ID's...

wdelements

Legacy Member
Ok, maar dat is net de vraag, hoe ik het het beste vertaal van database naar objectmodel :)

Dus als ik in de database een producttabel en een categorietabel zou hebben en ik wil bijvoorbeeld een object maken van een product.

Dien ik dan zowel in de productklasse de categorieID te zetten en een object categorie (dus met de catID en de categorieomschrijving)

Want stel nu dat ik een nieuw product maak waarbij de categorie een keuzelijst is met als values een catID, dan ga ik toch gewoon doen:

$product = new Product($_POST['naam'],$catID);
en in de dataklasse
$DataProduct->insertProduct($product)
...
insert into product(naam,catID) values($product->naam,$product->catID)

Of is het voor bij het ophalen?
Dus select productnaam,catID,categorieomschrijving from tabel inner join categorie op producttabel

En dan van de opgehaalde categoriewaarden een categorie-object maken en van de opgehaalde productwaarden een productObject en het categorieObject aan het productObject toevoegen?

dJeez

Legacy Member
wdelements zei:
Want stel nu dat ik een nieuw product maak waarbij de categorie een keuzelijst is met als values een catID, dan ga ik toch gewoon doen:

$product = new Product($_POST['naam'],$catID);
Neen, dat ga je niet doen. Je gaat niet werken met de ID, je gaat werken met een categorie object.

Wat je gaat doen is een nieuw product object creëren, en dan zeggen dat de categorie een bepaalde categorie is, summier (zoals in Propel voor de gemakkelijkheid) :

PHP:
// Een categorie creëren - je kan er uiteraard ook 1 ophalen uit de DB
$category = new Category();
$category->setName("Categorie 1");
$category->save();

// Een product creëren - en koppelen aan een categorie
$product = new Product();
$product->setName("Product X");
$product->setCategory($category);
$product->save();

Dit is er uiteraard vanuit gaande dat een product slechts tot 1 categorie kan behoren. Je zou de link overigens ook anders kunnen leggen (en een product toewijzen aan een categorie ipv - zoals hierboven - een categorie toe te wijzen aan een product).

wdelements

Legacy Member
Ok bedankt voor het voorbeeld, dus idd echt met objecten werken en niet met ID's
Ik was gewoon door een paar dingen in de war:

1.Doordat Fraggie zei dat het niet logisch is dat een categorie in een product zit, wat uiteindelijk toch wel zo is dan?

2.Je zegt dat Propel ook de categorieID in de class zal steken, waarom heb je deze dan toch nodig in de class als je met het object categorie moet werken?

dJeez

Legacy Member
wdelements zei:
1.Doordat Fraggie zei dat het niet logisch is dat een categorie in een product zit, wat uiteindelijk toch wel zo is dan?
Het specifieke design hangt van de use case af. Zoals ik zei : het voorbeeld gaat enkel op indien een product slechts aan 1 categorie kan toegewezen worden. Als dat niet klopt, klopt het model niet en moet je het dus bijschaven.

wdelements zei:
2.Je zegt dat Propel ook de categorieID in de class zal steken, waarom heb je deze dan toch nodig in de class als je met het object categorie moet werken?
Ik zei er ook bij dat dat voor lazy loading gedaan wordt. In het geval van lazy loading zal de inhoud van het categorie object slechts geladen worden als je die effectief nodig hebt. Als je dus een product (of meerdere producten) gaat laden dan zal die in eerste instantie enkel de productgegevens en ID van de gelinkte categorie ophalen. Pas als je dan via een product een categorienaam zou willen gebruiken (om weer te geven in een view vb.) zal het gelinkte categorie object ff gehydrated (ik ken de NL benaming niet echt die hiervoor gehanteerd wordt - lees enkel in 't Engels :p) worden. Om te zien hoe dat allemaal precies werkt kan je best gewoon eens een voorbeeld bekijken. Maar dit is dus iets dat optioneel is...

wdelements

Legacy Member
Ok bedankt.
Door ermee te beginnen is mij veel duidelijk geworden :)

Toch ben ik nog aan het worstelen met de categorieID, want stel nu de volgende situatie:
Een pagina met een invulveld voor de productnaam en een keuzelijst met values voor de categorie.
Je krijgt dan de productnaam via $_POST['naam'] en de categorieID via $_POST['categorieID'];
Dan zou je eigenlijk een categorieObject moeten gaan maken, daarop setID doen en dit toevoegen aan het product.
Terwijl je dan toch gemakkelijker gewoon de categorieID kunt zetten?
Of in het geval van ophalen uit de database, als je eerst de categorie ook nog moet gaan ophalen in de database en dan setCategory op het product moet gaan doen, ga je dan niet te omslachtig te werk en een query uitvoeren die niet hoeft?



Dan heb ik ook nog een vraag ivm volgende situatie:
IK heb nu reacties toegevoegd aan een product.

Dus de klasse product heeft volgende velden:
$productID
$productNaam
$categorie (object)
$reacties (een array van reactie objecten)

Stel dat ik nu een product opvraag via een url: http://www.website.be/producten/1/

dan zeg ik $product = DataProduct->getProduct($productID) ($productID = de 1 uit de url dus)

In de dataklasse vul ik dan het product op met de nodige velden, het categorie object en de reactie objecten die bij het product horen in een array.

Bij het oplijsten worden alle reacties getoond en indien ingelogd als admin staat er een knop "wissen" bij.
Achter deze knop zit een post die het te wissen id doorgeeft.

Hoe is dit in fatsoenlijk oo af te handelen?
Mag je dan wel gewoon doen $dataReacties->wisReactie($_POST['reactie_id']);
en vervolgens weer $product = DataProduct->getProduct($productID) doen en alles tonen ?

Of maak je een reactie object aan wat je vervolgens wist?
Dus $reactie = new Reactie();
$reactie->reactieID = $_POST['reactie_id'];
$dataReacties->wisReactie($reactie);

dJeez

Legacy Member
Om een reactie te verwijderen ga je de specifieke reactie ophalen op basis van zijn ID en roep je er dan de delete() methode van aan, dus iets als volgt (wederom als je Propel gebruikt) :
PHP:
$reactieId = (int)isset($_POST['reactie_id']) ? isset($_POST['reactie_id'] : -1;
$reactie = ReactieQuery::create()->findPK($reactieId);
if ($reactie != null) {
  $reactie->delete();
}
Er zijn ook betere sanity checks mogelijk dan wat hierboven staat uiteraard, maar 't is maar een voorbeeldje :p.

Hetzelfde principe (zonder de delete call uiteraard) kan je gebruiken om een categorie te koppelen aan een product.

sarnath

Legacy Member
Over deze issues is heel wat discussie mogelijk.
Zo heb je bij Microsoft Entity Framework ook de discussie over het gebruik van foreign keys ipv object referenties.
Hier is een interessant artikel:Foreign key vs. Independent associations in Entity Framework 4 | Code through the pain

Het is een issue waar de meningen nogal over verdeeld zijn.
Stel dat je een categorie wil toekennen aan een product en als volgt het product wil opslaan, dan ga je inderdaad het id van de categorie in de productentabel opslaan en heb je geen volledig categorie-object nodig.

Het is dan in principe ook niet prestatiebevorderend om eerst een categorie object te gaan ophalen t.o.v. gewoon het id toe te kennen en dit te gaan opslaan.
Maar het id toekennen is inderdaad dan weer tegenstrijdig met het oo-model.

Het bewijst in ieder geval maar weer de complexiteit van een goed gestructureerde database in combinatie met een objectgeoriënteerd model.

Moto

Legacy Member
Maar het id toekennen is inderdaad dan weer tegenstrijdig met het oo-model
Tja welke prijs wint ge met een site die gebaseerd is op een perfect academisch geimplementeerd oo-model?
Als dat minder pragmatisch en/of minder perfomant gaat zijn?
Programmeren is dingen maken voor mensen om te gebruiken, en ik merk het niet als een site oo of niet oo is ze :p

Zaken zoals niet op Id werken en op objecten "omdat dat OO is", heeft voor een site geen enkel maar dan ook geen enkel praktisch nut.

sarnath

Legacy Member
Moto zei:
Tja welke prijs wint ge met een site die gebaseerd is op een perfect academisch geimplementeerd oo-model?
Als dat minder pragmatisch en/of minder perfomant gaat zijn?
Programmeren is dingen maken voor mensen om te gebruiken, en ik merk het niet als een site oo of niet oo is ze :p

Zaken zoals niet op Id werken en op objecten "omdat dat OO is", heeft voor een site geen enkel maar dan ook geen enkel praktisch nut.

Daar ben ik het voor alle duidelijkheid volledig mee eens.
Programmeren is geen exacte wetenschap, anders zou iedereen (goed) kunnen programmeren.
Tegenwoordig kan iedereen bij wijze van spreken websites maken, zolang ge weet waar ge mee bezig zijt en waarom ge bepaalde zaken op een bepaalde manier doet dan is het in mijn ogen ok hoe het gemaakt is.
Natuurlijk moet ge ook altijd rekening houden met de beperkingen en de mogelijkheden van een framework/orm/... waar ge mee werkt.
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan