[OOP] Het beginnen met OOP
Na al enige tijd actief te zijn met php is het nu dan eindelijk tijd om het te leren. Niels zei een jaar geleden al dat ik dit moest doen, maar toen liet tijd en zin het zich afweten.
Nu ga ik er voor en neem ik de tijd.
Ik wil graag een simpele vorm van een cms maken in OOP. Het zal niet meer zijn dan een verzameling van klassen die op hun beurt de website controleren zodra de gebruiker dit zegt.
Ik heb het een en ander uitgewerkt en hoop eigenlijk dat jullie mij kunnen vertellen of ik op de goede weg zit.
Volledig versie van mijn eerste stappenplan vind je hier
Code (php)
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
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
Login
Gebruikersnaam
Wachtwoord
Controleer_gebruiker()
Gebruiker
Naam
Achternaam
Gebruikersnaam
Wachtwoord
Wijzig_gebruiker()
Plaats_nieuws()
Wijzig_nieuws()
Verwijder_nieuws()
Plaats_afbeelding()
Wijzig_afbeelding()
Verwijder_afbeelding()
Administrator (gaat verder op gebruiker)
Verwijder_gebruiker()
Plaats_gebruiker()
Pagina
Paginatitel
Tekst
Auteur
Weergeven()
Opslaan()
Nieuws
Titel
Tekst
Auteur
ToevoegDatum
Weergeven()
Opslaan()
Afbeelding
Naam
Extensie
Opslaglocatie
Afmetingen
Alternatieve tekst
Weergeven()
Opslaan()
Gebruikersnaam
Wachtwoord
Controleer_gebruiker()
Gebruiker
Naam
Achternaam
Gebruikersnaam
Wachtwoord
Wijzig_gebruiker()
Plaats_nieuws()
Wijzig_nieuws()
Verwijder_nieuws()
Plaats_afbeelding()
Wijzig_afbeelding()
Verwijder_afbeelding()
Administrator (gaat verder op gebruiker)
Verwijder_gebruiker()
Plaats_gebruiker()
Pagina
Paginatitel
Tekst
Auteur
Weergeven()
Opslaan()
Nieuws
Titel
Tekst
Auteur
ToevoegDatum
Weergeven()
Opslaan()
Afbeelding
Naam
Extensie
Opslaglocatie
Afmetingen
Alternatieve tekst
Weergeven()
Opslaan()
Ik heb graag kritiek op wat ik goed / fout doe. Ook hoor ik graag als ik iets vergeten ben. Wat betreft de opslag, dit zal in een database gebeuren, moet ik hier een simpele klassen voor schrijven die connectie maakt en eentje die toevoegt etc.
Alles wat ik hier heb staan heb ik gevolgd aan de hand van een OOP tut op webdevils, maar als ik dan vervolgens dat van Wouter ga lezen moet ik volgens mij de user class opsplitsen in een User en een Usermapper.
De mapper zorgt dan voor de toevoeg functies etc.?
Gewijzigd op 08/01/2013 19:19:08 door Milo S
Wat ik je wel nog wil meegeven is heel tegenstrijdig, namelijk het gebruiken van overerving en het juist voorkomen van overerving. Overerving is een erg mooi principe van OO, maar het wordt door beginners vaak te veel toegepast en dan moet je juist weer van de meeste overerving afstappen.
Laten we beginnen met de Administrator. We zouden zeggen dat de Adminitstrator een User is en we hem dus de user laten extenden. Alleen dat is verkeerd, we zullen hier een ander basisprincipe van OO moeten gebruiken: Haal het geen dat variabel is uit de constante klasse Hiermee bedoel ik dat het enige verschil tussen de User en de Administrator de rechten zijn, de rest blijft constant. Ipv een hele klasse dan te extenden is het beter 1 User klasse te maken die weer een extra property krijgt met daarin zijn rechten. Deze rechten splits je dan op in weer hun eigen klasse (Roles, een UserRole en AdminRole en AnonymousRole bijv.).
Dan gaan we naar het verschil tussen de pagina en de nieuws klasse. Dit zijn 2 totaal andere objecten, maar wel met 1 verschillende uitbreiding, namelijk dat de Nieuws klasse een publishdate heeft. Je kunt dan beter zeggen dat de Nieuws klasse een Pagina is met een publishdate en dat de Nieuws klasse dus de Pagina extend.
Vervolgens wil ik nog een basis principe erin gooien: Altijd programmeren naar een interface Hiermee bedoel ik dat elke klasse een Interface boven zich moet hebben. Dit maakt later de controle strict, maar flexibel en daarmee zorg je voor uitbouw.
Zorg dus dat een Afbeelding extend van bijv. een MediaInterface en pagina van een PageInterface, ect. In deze interfaces leg je vast welke methoden je echt perse nodig hebt. In het geval van de MediaInterface zou ik bijv. een render method (die het media object omzet in HTML code) in de interface zetten.
Dan nog even over de methoden, dat gaat bij sommige dingen goed mis (Voornamelijk de user klassen). Methoden kunnen alleen aanpassen wat hun object als eigenschappen heeft. Methoden als Gebruiker::wijzig_nieuws is OO technisch compleet verkeerd. Wat je doet is dat je een NieuwsManager bouwt, deze checked of de huidige user wel de juiste rechten (roles) heeft om deze actie uit te voeren.
Ook zou ik bij bijv. Pagina geen weergeven methode plaatsen, allerlei getters voor de properties zijn hier meer geslaagd. Je kunt dan in de view gaan bepalen hoe de post eruit komt te zien in bijv. HTML code (kan ook bijv. XML voor RSS zijn).
Dan het communiceren met de database: Een DataMapper (zoals UserMapper) is een schakel tussen het object en de database. Je zou dus de save method uit de klassen moeten slopen en die in de DataMapper plaatsen, samen met alle andere methoden die met de DB te maken hebben. Voorbeelden hiervan zijn er in overvloed: Voorbeeldje van Pim, uitleg + voorbeeld van mij en een wat meer technische uitleg van VeeWee
Beslagen ten ijs komen. Zo noemt men dat toch?
Als ik je opmerking over het extenden van de user -> administrator klasse goed begrijp dan moet ik in dit geval juist niet extenden gezien dat er maar 1 verschil is. De rechten. Hier zou ik juist een aparte klasse voor moeten maken. Wat is dan het voordeel dat ik per recht (UserRole, AdminRole, AnonymousRole) een aparte klasse maak?
In geval van pagina's en nieuws zou ik juist wel moeten extenden. Als ik dat niet doe doe ik precies dat wat je voorkomen wilt, 2 keer hetzelfde schrijven.
Dat begrijp ik, dit houd het makkelijker om alles te bewerken, HTML output etc.
Een NewsManager communiceert dus eigenlijk met Roles (welke communiceert met User) om te kijken of een actie uitgevoerd mag worden. Bijvoorbeeld het plaatsen van een bericht. Voert de NewsManager het dan ook uit of blijven we het dan toch echt hebben of nog een klasse, de NewsMapper in dit geval?
Quote:
Wat is dan het voordeel dat ik per recht (UserRole, AdminRole, AnonymousRole) een aparte klasse maak?
Dat je nu heel flexibel in je rechten bent. Je kunt er zo eentje bij voegen, aangeven waar die in het rechten systeem staat (bijv. AdminRole = 16, UserRole = 4 en Anonymousrole = 1). Ik kan dan bijv. nog een ModeratorRole toevoegen met 8 en een SuperAdminRole met 32.
Quote:
Een NewsManager communiceert dus eigenlijk met Roles (welke communiceert met User) om te kijken of een actie uitgevoerd mag worden. Bijvoorbeeld het plaatsen van een bericht. Voert de NewsManager het dan ook uit of blijven we het dan toch echt hebben of nog een klasse, de NewsMapper in dit geval?
Als je dit in een echte applicatie gaat maken dan zul je snel naar een (micro-)framework grijpen, of in elk geval naar een MVC pattern. Hierbij heb je dan controllers die een actie uitvoeren, deze zullen dan de NewsManager klasse vervangen en zelf kijken of de user de juiste rechten heeft, zo ja dan wordt de NewsMapper klasse aangeroepen om een nieuwsbericht te plaatsen, of iets anders.
Nog een maal ter bevestiging van de rechten.
De Role klasse verwijst een gebruiker dus naar de klasse van zijn rechten. Bijvoorbeeld AdminRole.
Moet ik in dit geval dan de Admin klasse extenden op een Moderator klasse enzovoort? Anders zou ik namelijk continu de constanten moeten overnemen (in de letterlijke zin typen dus...)
Edit
Het volgende heb ik er van gemaakt; hier
In de klasse User_Role, Mod_Role en Admin_Role vind je de constructor, deze zou dan een TRUE of FALSE moeten teruggeven wanneer een actie wel of niet uitgevoerd mag worden. Niet waar?
Zoals je ziet heb ik geen set methoden gebruikt, dit omdat dat naar mijn idee allemaal in de constructor thuis hoort. Zonder die variabelen hebben we namelijk nog niets. Of raden jullie dit af? Past dit binnen de OOP denkwijze?
Ik ga nog even zoeken op wat jij bedoelde met de interfaces wouter, maar daar google ik nog even op verder
Edit 2
Als ik het eens goed lees over interfaces dan bepaald dat eigenlijk alleen maar eisen waaraan een child classe aan moet voldoen.
Bijvoorbeeld een UserInterface geeft aan dat je altijd een gebruikersnaam en wachtwoord moet kunnen ophalen. De User klasse voldoet hier dan aan anders werkt het gewoon niet?
Gewijzigd op 08/01/2013 20:38:34 door Milo S
Gezien ik toch wel met deze vragen blijf zitten en gewoon super nieuwsgierig ben bump ik toch maar even...