OOP model in class
Zelf dacht ik aan zoiets als dit:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$id = $_SESSION['userid'];
$model = new UserModel($db_conn);
$user = new User($id, $model);
?>
$id = $_SESSION['userid'];
$model = new UserModel($db_conn);
$user = new User($id, $model);
?>
Is het bovenstaande een gebruikelijke manier? Ik zie namelijk ook wel eens dit:
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
<?php
$id = $_SESSION['userid'];
$model = new UserModel($db_conn);
$user = new User($id);
$user->loadModel($model);
?>
$id = $_SESSION['userid'];
$model = new UserModel($db_conn);
$user = new User($id);
$user->loadModel($model);
?>
Weet iemand dit toevallig?
En nog een laatste vraag ... "mag" je het ID ook meegeven aan het UserModel in plaats van aan de User class?
Of is dat niet gebruikelijk?
Ik vraag dat omdat als ik het ID mee zou geven aan het UserModel, ik in de constructor van het model meteen alle gegevens zou kunnen ophalen uit de database en die als property zou kunnen opslaan. Als ik het ID meegeef aan de User class zelf (zoals nu het geval is) dan moet de User class het ID eerst doorgeven aan het UserModel en moet er vanuit de User class een functie in het UserModel worden aangeroepen die de data ophaalt.
Wat is "gebruikelijk"?
Gewijzigd op 11/02/2019 17:12:28 door Ozzie PHP
Als het dan toch nodig is om op een of andere manier een soort van combinatie te hebben of dat er een verband is, zou het dan niet logischer zijn dat de User class extend van de Model class?
Nope ... een 'extend' wil zeggen een "is een" relatie. Bijv. Admin extend User ... een admin is een user.
Door te werken met een model scheidt je de "intelligentie" van de class zelf. Je kan het model dan wisselen door een ander model terwijl de functionaliteit hetzelfde blijft. In dit geval geef je via de User class aan WAT er moet gebeuren, en het model regelt vervolgens HOE dat gebeuert. De User class heeft daar geen weet van.
Pff, ziet er veel te ingewikkeld uit :-) Ik wil het simpel houden ;-)
- 90% van de tijd is alles gewoon precies hetzelfde (in alle projecten). Ipv DI kun je dan gewoon extenden, want je wijzigt toch nooit het achterliggende model (ook gewoon een DI container - hoef je bijna nooit te injecten).
- Als je dan eens een keer wat anders wilt "in de basis" leg je er gewoon een trait overheen die de juiste methods modificeert (als jet het al niet met een tussenlaag kunt: normaal User extends UserModel; uitzondering: User extends SpecialUser extends UserModel).
Maar dit klopt niet. Een User is geen Model. Dit is fout gebruik van OOP.
Er worden allerlei abstractie-lagen op elkaar gestapeld, maar uiteindelijk wil je de gebruikersgegevens uit de database in een variabele, toch?! Enfin, doe dat en als je twijfelt bekijk dan het resultaat van je code (echo, var_dump, print_r, ...)
Als een UserModel een model van een gebruiker is en een User géén model is, wat is een User dan wel?
Ik snap je opmerking niet helemaal ...
@Ward
Een User is gewoon een User class, een representatie van een User. Het model is het model dat bepaalt hoe de data wordt opgehaald. Door een ander model aan de User class te koppelen, kan data op een andere manier worden opgehaald. De User class praat dus als het ware met het model (geef mij de username, geef mij de voornaam enz.), maar weet verder niet hoe het model die data ophaalt, laat staan waar die data vandaan komt. Dat is toch het idee van een model?
Maar een model IS niet een User.
Vaak zie je constructies als User extends Database, omdat men in de User class een database nodig heeft. Ook dit klopt weer niet, want een User IS geen database, en ook geen model.
Wat ik bedoel is dat je normaal gesproken bij het ontwerp van software eerst gaat bepalen welke objecten je nodig bent en welke Classes je daarvoor gaat inrichten. Kortom, net in omgekeerde volgorde van jouw vraagstelling. Anders schiet je aan het doel van OOP voorbij. Code die volgens OOP invalshoek is ontwikkeld zou namelijk makkelijk(er) leesbaar, interpreteerbaar en uitbreidbaar moeten zijn.
Heb het inmiddels al min of meer opgelost volgens een eigen interpretatie, maar ik dacht dat er wellicht wat richtlijnen waren die ik kon volgen.
Quote:
Een User is gewoon een User class, een representatie van een User.
Het model is het model dat bepaalt hoe de data wordt opgehaald.
Het model is het model dat bepaalt hoe de data wordt opgehaald.
Dus User is een Controller.. Die kan nooit extenden op een model.
Bij het model geef je bijna het juiste antwoord.
Die kan inderdaad uit de achterliggende lagen wat halen.
Extenden op een database is niet goed. Want een model zou niet moeten weten of het een database is of XML of andere data.
Dus class UserModel extends Model, En Model regelt de rest WAT er moet gebeuren en waat het vandaan kan komen. Moeilijk is het niet, alleen een beetje overnadenken.
Vergeet ook niet OOP is een ding om het jezelf makkelijker te maken en overzichtelijk.
Als iets makkelijker is om het anders te doen en het werkt en is overzichtelijk, veilig, en logisch dan is dat ook goed he.
>> Dus User is een Controller.. Die kan nooit extenden op een model.
Precies! Dat is wat ik al zei. Gelukkig had ik het dus bij het rechte eind.
>> Extenden op een database is niet goed. Want een model zou niet moeten weten of het een database is of XML of andere data.
Dit vind ik wel interessant. Ik laat het model niet extenden op een database (immers, een model IS geen database). In plaats daarvan geef ik de database mee aan het model via de constructor.
Nu zeg jij "Want een model zou niet moeten weten of het een database is of XML of andere data."
Dat vind ik wel even een lastige, want in mijn UserModel moet ik data ophalen uit de database en dus moet ik in het UserModel queries uitvoeren. Het model weet dus dat het een (in dit geval MySQLi) database meekrijgt. Ik zou niet weten hoe je dat (handig) op een andere manier zou moeten oplossen eigenlijk.
>> Als iets makkelijker is om het anders te doen en het werkt en is overzichtelijk, veilig, en logisch dan is dat ook goed he.
Dat is zeker waar. Ik zie vaak gruwelijk ingewikkelde constructies, en daar ben ik JUIST niet naar op zoek. Ik zoek simpele methodes die makkelijk te interpreteren zijn, maar waarmee ik wel het idee / het nut van OOP (alles centraal en makkelijk uit te breiden) in stand houd.
Ozzie PHP op 13/02/2019 13:01:21:
... want in mijn UserModel moet ik data ophalen uit de database en dus moet ik in het UserModel queries uitvoeren. Het model weet dus dat het een (in dit geval MySQLi) database meekrijgt.
Dan zou je dus met een DI container kunnen gaan werken. Dan geef je gewoon de hele container mee, en het model ziet maar uit welk potje ie z'n data haalt. Wordt het allemaal wel een beetje "losjes" gekoppeld van.
Ik snap het nog steeds niet. Er moeten queries zijn die data uit de database ophalen. Die queries moet ik toch in het model plaatsen? Waar zou ik ze anders dan moeten plaatsen?
In die container zit (oa) een instantie van je database. Als het model wat je op dat moment gebruikt queries uit moet voeren pakt het dus de database uit de container. Moet de data ergens anders vandaan komen, dan pakt ie whatever nodig is om dat te doen.
Bart v B zei hierboven: "Want een model zou niet moeten weten of het een database is of XML of andere data.".
Hoe je vanuit het model een database aanspreekt snap ik. Wat ik bedoelde is ... om gegevens uit de database te kunnen halen moeten er queries worden uitgevoerd. Die queries moeten toch in het model staan? Anders gezegd, het model weet dan toch dat het data ophaalt uit een database?
Gewijzigd op 14/02/2019 10:37:06 door Ozzie PHP
Ozzie PHP op 11/02/2019 17:08:14:
Waarom gebruik je geen data mapper? Dan krijg je zoiets, dat lijkt op het bovenstaande:
Code (php)
1
2
3
4
2
3
4
<?php
$user_mapper = new UserMapper($storage);
$user = $user_mapper->getUserById($_SESSION['user_id']);
?>
$user_mapper = new UserMapper($storage);
$user = $user_mapper->getUserById($_SESSION['user_id']);
?>
In dit geval is User wél een model, maar een model dat niet hoeft te weten waar en hoe de data worden opgeslagen: dat is de verantwoordelijkheid van de UserMapper.
Maar hoe vraag ik in jouw voorbeeld dan bijvoorbeeld het e-mailadres van de User op?
In jouw plaatje lijkt User een class, maar in het codevoorbeeld maak ik dat niet eruit op.
Het hangt er dus vooral van af hoe complex je UserModel is. Bestaat het model vooral uit getters en setters die overeenkomen met kolommen in dezelfde tabel (bijvoorbeeld `email` in een tabel `users`), dan is een data mapper een efficiënte en effectieve oplossing.
Om het voorbeeld verkort uit te breiden met een e-mailadres: