[OOP] Implementeren admin functie
Ik wil graag even sparren over een probleem.
Ik heb 3 klassen. Person, User en Admin.
Person is abstract
User en Admin overerven Person.
Op moment dat ik inlog wil ik op 1 of andere manier dat de klassen Person (de klasse met de constructor) zelf bepaald of het een User of een Admin is.
Een gebruiker moet in dit geval enkel de User functionaliteit hebben.
Maar de beheerder de Admin functionaliteit.
De klasse Person bevat alle persoonsgegevens + username, access level
Kortom, hoe kan ik het voor elkaar krijgen dat wanneer ik enkel een gebruiker id heb een nieuwe instantie aanmaak en deze zelf bepaald of hij een User is of dat het een Admin is?
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Uiteraard kun je alles gebruiken voor het bepalen van de access leves, dit is slechts een voorbeeld. Ik neem aan dat je deze gegevens in een DB hebt staan? Dus de gebruikers/admins zullen een veld access_level of iets dergelijks hebben?
En om bepaalde pagina's te beperken tot admin kun je het access level ook toevoegen aan een sessie. En dan vervolgens zoiets gebruiken per pagina.
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
<?php
session_start();
if (isset($_SESSION['alevel']) $$ $_SESSION['alevel'] == 44) {
//Laad admin pagina hier
} else { header ("Location: onbevoegd.php"); }
?>
session_start();
if (isset($_SESSION['alevel']) $$ $_SESSION['alevel'] == 44) {
//Laad admin pagina hier
} else { header ("Location: onbevoegd.php"); }
?>
Gewijzigd op 16/05/2012 08:41:38 door Chris PHP
Ja dat kan ik inderdaad doen. Maar probeer wel het SOLID principe aan te houden..
Daarnaast niet echt OOP om met if else te gaan bepalen wat voor object je moet aanmaken...
Met andere woorden, ik wil eigenlijk gewoon een user id meegeven en de klasse zelf laten uitzoeken of hij een Admin is of een User...
Wellicht moet ik met een Interface werken...
waarde uit de database en zet je dit in een sessie? Dat is sneller en makkelijker.
Maar wat je in eerste instantie vraagt lijkt me een beetje onmogelijk. Als de klasse Person abstract is, dan kan die niet bepalen welke child-klasse aangemaakt gaat worden. Volgens mij kan dat uberhaupt niet, een geovererfde klasse laten bepalen welke child-klasse geinstantieerd wordt.
Wat je wel zou kunnen doen, is de verschillen tussen User en Admin entiteiten in apparte klassen opvangen en niet in children van Person. In die klassen bepaal je bijvoorbeeld of acties mogen worden uitgevoerd en of bepaalde data beschikbaar is. In de klasse Person neem je dat object op als een variabele. Volgens mij is dit een beetje het Dependency Injection principe (hoewel ik daar geen expert in ben).
Bij het instantieren van Person bepaalt Person (of een factory die Person aanmaakt) welke klasse wordt meegegeven en dus welke functionaliteit beschikbaar is. Als beide User en Admin klasse dezelfde Interface delen dan hoef je verder binnen Person nooit meer met conditionele statements te werken, dat wordt geregeld door welke klasse is meegegeven.
http://en.wikipedia.org/wiki/Factory_method_pattern
Kort samengevat:
Je maakt een Factory klasse.
Hier neem je dan bijvoorbeeld een statische create functie met als parameter uw access level. In die create functie ga je dan zien welk object je moet bouwen. User of Admin.
Je krijgt dus altijd een instantie van Person terug.
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
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
Gewijzigd op 16/05/2012 13:57:10 door de VeeWee
En hoe komt x of y aan de waarde wat de gebruiker nu is?
En hoe gebruik je dit dan verder in de site om te kijken welke pagina voor welke gebruiker te benaderen is?
Ik ben net bezig met OOP, dus ben daar wel benieuwt naar.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// haal gegevens op uit database:
$tbl = new Table_Persons();
$data = $tbl->getByCredentials($email, $password);
// haal het object op:
// let op: die $data is nu een array of object geworden met een rij uit de database
// zie verder onderaan
$person = Person_Factory::create($data);
// hoe weten welke gebruiker het is?
$isAdmin = ($person instanceof Admin);
$isAdmin = $person->isAdmin();
// natuurlijk idem voor gebruiker
// die isX functie moet dan in het Person object zitten
?>
// haal gegevens op uit database:
$tbl = new Table_Persons();
$data = $tbl->getByCredentials($email, $password);
// haal het object op:
// let op: die $data is nu een array of object geworden met een rij uit de database
// zie verder onderaan
$person = Person_Factory::create($data);
// hoe weten welke gebruiker het is?
$isAdmin = ($person instanceof Admin);
$isAdmin = $person->isAdmin();
// natuurlijk idem voor gebruiker
// die isX functie moet dan in het Person object zitten
?>
Create functie:
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
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
<?php
/**
* @return Person
*/
public static function create($data)
{
// create object
switch ($data['accessLevel']) {
case 'x':
$person = new User();
break;
case 'y':
$person = new Admin();
break;
default:
throw new Exception('invalid accesslevel');
}
// add data
// hier kan je eventueel ook een mapper klasse voor gebruiken
$person->setId($data['id']);
// ....
return $person;
}
?>
/**
* @return Person
*/
public static function create($data)
{
// create object
switch ($data['accessLevel']) {
case 'x':
$person = new User();
break;
case 'y':
$person = new Admin();
break;
default:
throw new Exception('invalid accesslevel');
}
// add data
// hier kan je eventueel ook een mapper klasse voor gebruiken
$person->setId($data['id']);
// ....
return $person;
}
?>
Gewijzigd op 16/05/2012 14:14:01 door de VeeWee
De VeeWee op 16/05/2012 14:11:11:
Dit betekent dat gebruik van het object afhankelijk wordt van de klasse. Wat je eigenlijk wilt, is dat je zowel User als Admin kan gebruiken zonder dat je hoeft te weten wat voor klasse het precies is. Met andere woorden, je krijgt van de factory een object terug wat alles kan wat je wilt doen, zonder je verder zorgen te hoeven maken over implementatie. Als je nu klasse specifieke methodes gaat implementeren dan werkt dat niet meer.
Als je al zoiets nodig hebt, dan zou ik een algemene methode in de interface definieren (iets als 'whatAmI') die dan een string of integer teruggeeft die aangeeft wat het object is. Op die manier blijft de aanroep hetzelfde, onafhankelijk van welke klasse is geinstantieerd.
In de sql database een rechten kolom aanmaken. en vervolgens op dat resultaat gaan kijken in een tabel rechten_functie daar staat dan het rechten nummer + de functie maar je blijft een if else houden. Wanneer je veel functies hebt is dit erg handig.
Over die isX() heb je wel gelijk. Maar overerving wordt ook gebruikt om extra functionaliteit in de klasse te plaatsen. Je moet er wel van uit gaan dat je in de rest van je project wel weet over welk type gebruiker het gaat. Uw admin object zal andere dingen kunnen doen als uw user object... Je moet het dus ook niet TE abstract bekijken. Maar ok, dat hangt dan natuurlijk ook weer af van wat je juist wilt bereiken natuurlijk.
Maar je hebt gelijk, de isX() functies gebruik ik normaal ook enkel voor een bepaald veld in de database. Bijvoorbeeld: isActive(), isDeleted(). instanceof zal dus in dit geval wel beter zijn.
Bedankt voor je antwoord.
Ik kan me zeker vinden in het factory pattern. Had niet stilgestaan om dit gebruiken.
Wat betreft depencency injection. (Interface verwachten) waarop je bepaalde methodes aanroept die in de interface zitten.
Welke hier wordt gebruikt is niet duidelijk, dus is het een ontwerp keuze hoe je het doet. Eens.
Toevoeging op 16/05/2012 15:48:01:
@Wim
Precies, volgens mij is dat een goed pattern voor het ontwerp waar jij mee zit. Tenzij je enorm veel extra functionaliteit in een van beide wilt hebben. In dat geval zou ik dus User en Admin geen kinderen laten zijn van Person.