[PHP,OOP] Mijn eerste klasse - wat erbinnen en wat erbuiten?

Pagina: 1
Acties:
  • 776 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • oscarvdb
  • Registratie: December 2001
  • Laatst online: 20-05 09:45

oscarvdb

and like that...

Topicstarter
Ik heb besloten mijn eerste klasse te gaan schrijven; klasse Login. Nou ben ik het eerst in mijn hoofd aan het uitdenken. Daarbij stuit ik op wat vragen.
  1. Het moet dus mogelijk zijn om met een formulier in te loggen. Moet ik de HTML van dat formulier binnen mijn klasse zetten, en dan aanroepen met iets als <? $login->showLoginForm(); ?>, of moet dit buiten de klasse en wordt alleen het resultaat daarvan (de credentials dus) in de instantie van de klasse gezet?
  2. Wat is verstandiger:
    PHP:
    1
    2
    3
    4
    5
    
      $login->setUser($_SESSION['user']); //de sessie buiten de klasse aanroepen
     
      // OF:
     
     $login->setUser(); //en dan binnen de klasse de sessie aanroepen 
  3. De beveiliging zelf, moet dan zoiets boven elke pagina:
    PHP:
    1
    2
    3
    4
    5
    
      if($login->getLoggedIn() == 0) 
      { 
        // error laten zien en dan: 
        exit; 
      }

    Of zou dat op een andere manier beter zijn?
Alvast bedankt :9

... he's gone.


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Goede princiepes voor classes is te bedenken wat je je class wilt laten representeren. Enkele mogelijke opties voor classes die ik uit jouw verhaal kan afleiden zijn: User, LoginForm en Login. Het is verder goed om een class 1 duidelijke taak te laten hebben. Een User class is bijvoorbeeld een representatie van een gebruiker, dat heeft verder niets met het formulier te maken of de manier waarop ingelogd wordt. Beter is dus om die 2 ook apart te maken. Een LoginForm class zou dan een pagina zijn waarin je login formulier zit. Los daarvan zou ik dan ook het werkelijke inloggen houden, in de class Login bijvoorbeeld. Die class kun je dan instantieren met de juiste gegevens (username, password etc.) en dan de transactie uitvoeren. Als resultaat zou je dan ook een User object kunnen ophalen.

Een goede manier om te kijken is of je methodes goed passen bij hetgeen je wilt representeren met je class. Je hebt bijvoorbeeld een Login class. Dat is dus een bepaald process dat je in het begin van je app doorloopt. Is het normaal om daaraan te vragen of de gebruiker ingelogd is? Lijkt mij eerlijk gezegd niet. Het lijkt eerder normaal om dat aan de gebruiker (User) zelf te vragen. Ik hoop dat ik je zo een beetje geholpen heb.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 14:45
Zoals Michali al zegt, moet je eerst eens nadenken wat je met je class wilt voorstellen.
Een class 'Login' vind ik een beetje raar. Ik bedoel: dat wringt een beetje. 'Login' is imo een operatie. Een gebruiker voert de operatie 'Login' uit, of, er wordt een Login operatie uitgevoerd, en deze operatie levert, als het goed is, een gebruiker op.

Bv:
code:
1
User theUser = User.Login (username, password);


Waarbij Login een static method is van de class User. Of, je kan ook eerder zo iets doen:
code:
1
2
UserRepository rep = new UserRepository();
User theUser = rep.Login (username, password);


Als je een class maakt die 'iets' voorstelt (bv een gebruiker), dan moet je in die 'gebruiker class' ook geen UI code gaan plaatsen, want, daar heeft die -in dit geval- gebruiker eigenlijk niets mee te maken.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • oscarvdb
  • Registratie: December 2001
  • Laatst online: 20-05 09:45

oscarvdb

and like that...

Topicstarter
Misschien is mijn benaming voor de klasse wat vreemd. Ik wil niet alleen met deze klasse kunnen inloggen, maar ook kunnen bekijken of iemand ingelogd is, en bewerkingen uitvoeren als wachtwoord veranderen.

Dit moet ik dus opsplitsen in meerdere klassen?

... he's gone.


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Dat licht er aan waar het bij hoort. Als die handelingen echt horen bij wat je een User class wilt laten voorstellen, dan moet je ze daar wel bijhouden. Een User kun je laten inloggen en je kunt ook zijn wachtwoord veranderen, dat lijkt me dus een vrij goed teken dat je die zaken in 1 class kunt stoppen. Je zou kunnen beargumenteren dat inloggen een los process is, als je dat beter vindt dan kun je dat process idd naar een andere class verplaatsen. Iets als Login zou dan helemaal niet zo gek zijn. Maar je moet dan wel de class echt voor 1 ding gebruiken. Je gebruikt zo'n login dus puur voor het inloggen, en verder niets. Je vraagt er niet aan of een gebruiker ingelogd is, dat is meer iets voor de User zelf. Zoals whoami al zei, Login is echt een handeling en niet een werkelijk object. Het kan echter wel handig zijn. Als je tijdens het inloggen verschillende acties uitvoert die je niet in verband met je User wilt hebben, dan is het beter om dat in een aparte class te verpakken. Bovendien maakt dat het ook gemakkelijker om op verschillende plaatsen een Login actie uit te voeren.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • Guldan
  • Registratie: Juli 2002
  • Laatst online: 11:30

Guldan

Thee-Nerd

Je kan ook een klasse user maken met de basis gegevens van de user. Naam, loginnaam,Adres, Locatie,woonplaats etc. en deze dan extenden met een aantal klassen. Dus een klasse om de user te laten inloggen. Weer een andere klasse om hem een nieuws artikel te laten posten of zoiets. Maar dat is altijd een beetje dubieus want iedereen heeft er net iets andere ideen over.

You know, I used to think it was awful that life was so unfair. Then I thought, wouldn't it be much worse if life were fair, and all the terrible things that happen to us come because we actually deserve them?


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Niets mis met een Login class imho. Mooie duidelijke enkelvoudige functie. Dat een class altijd een entiteit moet zijn is natuurlijk onzin, het kan net zo goed een abstracte operatie voorstellen. Denk bv aan een equation solver, daar zet je bv een vergelijking en roep je solve aan. Ik zou niet een soort monolith user class maken met alle functionaliteit. Eerder dat de login class een referentie kan retourneren aan de user die is ingelogd op dat moment. Zo kan je ook nog een systeem opzetten waar meerdere users ingelogd kunnen zijn, en dat bijhoudt wie er allemaal zijn etc. Dat past allemaal netjes in je login class.

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Guldan schreef op zaterdag 17 december 2005 @ 13:22:
Je kan ook een klasse user maken met de basis gegevens van de user. Naam, loginnaam,Adres, Locatie,woonplaats etc. en deze dan extenden met een aantal klassen. Dus een klasse om de user te laten inloggen. Weer een andere klasse om hem een nieuws artikel te laten posten of zoiets. Maar dat is altijd een beetje dubieus want iedereen heeft er net iets andere ideen over.
Hoezo zou je een klasse van User laten extenden om een Artikel te posten? Je kan dan beter een Artikel class maken die een methode Post heeft ( waar je eventueel een User aan meegeeft ). Maar het is echt niet de bedoeling van OO dat je voor elke functionalteit een nieuwe sub-class maakt.

Dan zou ik eerder bijvoorbeeld een Gastenboek class maken die een Method Post heeft waar je weer een instance van een Artikel class aan meegeeft.
Zoijar schreef op zaterdag 17 december 2005 @ 13:42:
Niets mis met een Login class imho. Mooie duidelijke enkelvoudige functie. Dat een class altijd een entiteit moet zijn is natuurlijk onzin, het kan net zo goed een abstracte operatie voorstellen. Denk bv aan een equation solver, daar zet je bv een vergelijking en roep je solve aan. Ik zou niet een soort monolith user class maken met alle functionaliteit. Eerder dat de login class een referentie kan retourneren aan de user die is ingelogd op dat moment. Zo kan je ook nog een systeem opzetten waar meerdere users ingelogd kunnen zijn, en dat bijhoudt wie er allemaal zijn etc. Dat past allemaal netjes in je login class.
Dat klinkt idd een stuk beter. Dan hou de dingen waar Login verantwoordelijk voor is bij elkaar en kan je het ook makkelijk uitbreiden. Maar ik zou er zeker geen andere functionaliteit in opnemen die met andere delen van je site te maken hebben.

[ Voor 35% gewijzigd door Woy op 17-12-2005 13:44 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Lentje
  • Registratie: Juni 2001
  • Laatst online: 12-09 17:04
Misschien kan je het dan beter een user class noemen. Dat denkt de lading in jou geval wat beter denk ik.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 14:45
Zoijar schreef op zaterdag 17 december 2005 @ 13:42:
Niets mis met een Login class imho. Mooie duidelijke enkelvoudige functie. Dat een class altijd een entiteit moet zijn is natuurlijk onzin, het kan net zo goed een abstracte operatie voorstellen.
Nee, natuurlijk moet een class niet altijd een entiteit zijn.
Eerder dat de login class een referentie kan retourneren aan de user die is ingelogd op dat moment. Zo kan je ook nog een systeem opzetten waar meerdere users ingelogd kunnen zijn, en dat bijhoudt wie er allemaal zijn etc. Dat past allemaal netjes in je login class.
Mja.... Ik zou -denk ik- eerder een soort van user-management class maken, met daarin een login functie, die een user entiteit kan returnen, en andere methods waarmee je aan user - management kunt doen (creatie v/e user account, etc..).

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • oscarvdb
  • Registratie: December 2001
  • Laatst online: 20-05 09:45

oscarvdb

and like that...

Topicstarter
Lentje schreef op zaterdag 17 december 2005 @ 14:01:
Misschien kan je het dan beter een user class noemen. Dat denkt de lading in jou geval wat beter denk ik.
Dat is inderdaad al gezegd. De naam maakt voor de verdere discussie niet uit.
Twee klassen "User" en "Authentication" of deze in 1 klasse zetten?

Op dit moment zal het alleen gebruikt worden om bepaalde pagina's alleen toegankelijk te maken met goede credentials.

... he's gone.


Acties:
  • 0 Henk 'm!

  • JHS
  • Registratie: Augustus 2003
  • Laatst online: 16-09 16:02

JHS

Splitting the thaum.

Ik zou vanuit een MVC perspectief redeneren en een User class hebben en een LoginController :) .

DM!


Acties:
  • 0 Henk 'm!

  • NetForce1
  • Registratie: November 2001
  • Laatst online: 20-09 23:15

NetForce1

(inspiratie == 0) -> true

JHS schreef op zaterdag 17 december 2005 @ 14:49:
Ik zou vanuit een MVC perspectief redeneren en een User class hebben en een LoginController :) .
Voor de rechten-checks zou ik daar dan nog een SecurityController bij doen. Maar dat is dan misschien weer overkill als je alleen wilt kijken of iemand toegang heeft tot een bepaalde pagina.

De wereld ligt aan je voeten. Je moet alleen diep genoeg willen bukken...
"Wie geen fouten maakt maakt meestal niets!"


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Ik zou gaan voor een LoginAction class. Deze voert dan de werkelijke login actie uit en als resultaat kun je dan ook de user opvragen. Ook als je voor een MVC oplossing gaat (laten we even niet te ver gaan hierin, lijkt me voor de TS een beetje complex worden allemaal), dan zou ik ook die actie niet direct in de controller zetten. Wat de controller wel kan doen is de actie instantieren en uitvoeren. Iets als dit lijkt me wel netjes (PHP4 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
46
47
48
49
50
51
52
53
54
55
56
57
<?php

class User
{
    function User($username, $password)
    {
        // constructor
    }
    
    // username en password getters en setters
    
    function isLoggedIn()
    {
        return true;
    }
}

class NotLoggedInUser
{
    // getters en setters die null returnen etc.
    
    function isLoggedIn()
    {
        return false;
    }
}

class LoginAction
{
    var $username;
    var $password;
    var $user;
    
    function LoginAction($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
        $this->user = new NotLoggedInUser();
    }
    
    function execute()
    {
        $user = UserRepository.login($username, $password);
        if ( !is_null($user) ) $this->user = $user;
    }
    
    function getUser()
    {
        return $this->user;
    }
}

$loginAction = new LoginAction($_POST['username'], $_POST['password']);
$loginAction->execute();
$user = $loginAction ->getUser();

?>

Ik maak ook gebruik van het Null Object pattern, NotLoggedInUser in dit geval. Dat kun je ook op een andere manier oplossen als je dat wilt.

Wat je in ieder geval zeker niet moet doen, is een sub class maken voor iedere actie. Je moet sowieso heel voorzichtig omgaan met het aanmaken van sub classes. Een sub class moet altijd onder andere ook zijn super class voorstellen. Een pagina voor het posten van een nieuws artikel is natuurlijk niet een User. Het uitbreiden van de User class daartot slaat dan ook helemaal nergens op. Uiteraard kan zo'n class daar dan wel gebruik van maken, maar dan door middel van aggregatie. Aggregatie (zoals de LoginAction class bijvoorbeeld gebruik maakt van User) heeft ook altijd de voorkeur boven overerving. Behalve als je echt polymorphisch gedrag wilt bereiken, maar in php4 hoef je je daar ook niet al te druk om te maken, die is immers puur dynamisch getypeerd.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • JHS
  • Registratie: Augustus 2003
  • Laatst online: 16-09 16:02

JHS

Splitting the thaum.

NetForce1 schreef op zaterdag 17 december 2005 @ 15:19:
[...]Voor de rechten-checks zou ik daar dan nog een SecurityController bij doen. Maar dat is dan misschien weer overkill als je alleen wilt kijken of iemand toegang heeft tot een bepaalde pagina.
Mja, daarom stop ik die meestal in de ApplicationController waaruit de andere Controllers inheriten...

DM!


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Ik zou aan de TS eerst willen vragen wat hij denkt dat OOD inhoudt :? Volgens mij kan het geen kwaad om dat eens na te lezen. Een góed OOD ontwerp is erg moeilijk, moeilijker nog dan een goed ERD :). Wat wil je doen met het systeem?

Stel dat je de volgende beschrijving hebt: "Ik wil een applicatie (in dit geval een website) maken, waarmee gebruikers pagina's met informatie mogen bekijken".
Dan heb je de volgende entiteiten:
• gebruiker
• pagina
Applicatie valt af, aangezien dat hetgene is wat je gaat modelleren. "mogen bekijken" is een relatie tussen een gebruiker en een pagina. Aangezien je daar dingen aan wilt toewijzen zal je daar ook een klasse van objecten van willen maken (objectiveren genoemd).

Uiteraard is dit een te simpel voorbeeld. Je zal groepen gebruikers willen hebben, aangezien je niet per pagina de rechten per gebruiker in wil stellen.

De beschrijvingen hierboven zijn imho een stap of 2 te ver. Bij een simpele opdracht als deze kan je op basis van ervaring de tussenliggende stappen overslaan, maar het is wel zo handig om het te vermelden bij iemand die net begint, toch?
Ja, ik heb net weer les in 'modelleren' aan de TU/e (2IJ65) dus vandaar dat ik nog zo mooi de tussenstappen kan vertellen :P. Ik was ook al aan een userManager aan het denken, toen me ineens te binnen schoot dat de TS nog geen ERD had :)

Over vraag 2 trouwens: ik houd de klasses het liefste zo algemeen mogelijk. De checks komen in het formulier, om de User Interface van de Bussiness layer te scheiden. Dus de 2e manier. Ik zou als ik jouw was ook eens kijken naar de mogelijkheden van sessions: je kan gewoon die klasse erin proppen. Je slaat het immers op de server op :)

Dus om in te loggen:
code:
1
2
3
4
5
6
7
8
9
#require_once('general_classes.php');
session_start();
...
$username = doChecks($_POST['user']);
$passwd = doChecks($_POST['passwd']);
$user = $usermgr->login($username, $passwd);
$session['user']= $user;

...

En als je ingelogd bent:
code:
1
2
3
4
5
#require_once('general_classes.php');
session_start();
$user=$_SESSION['user'];

...

[ Voor 22% gewijzigd door MBV op 17-12-2005 16:59 ]


Acties:
  • 0 Henk 'm!

  • oscarvdb
  • Registratie: December 2001
  • Laatst online: 20-05 09:45

oscarvdb

and like that...

Topicstarter
Bedankt voor jullie commentaar allemaal. Ik ben niet zo thuis in al die terminologie, SRD zegt mij niets. Google vertelt me "System Reference Document" - dus een soort functioneel ontwerp van wat je wil gaan ontwikkelen?
MBV schreef op zaterdag 17 december 2005 @ 16:53:
Ik zou aan de TS eerst willen vragen wat hij denkt dat OOD inhoudt :?
Ik wil graag object geörienteerd werken omdat ik dan één klasse bij meerdere applicaties kan gebruiken. In dit geval: de loginmodule in meerdere websites kan implementeren.

Maar goed, dit heb ik tot nu toe.
Het werkt, kunnen jullie misschien aangeven wat anders moet of wat efficiënter/beter kan gebeuren?

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class Authentication
{
    public $username;
    public $passwordMD5;
    public $matchedId;
    public $table;
    public $loginURL;
    
    function __construct()
    {
        // nog leeg...
    }

    // tabel setten waar de userinfo in verstopt zit
    function setTable($givenTable = "")
    {
        $this->table = $givenTable;
    }
    
    // URL setten waar de gebruiker heen moet indien fout.
    function setLoginURL($loginURL = "")
    {
        $this->loginURL = $loginURL;
    }


    // poging tot login: controle username en wachtwoord, indien goed, sessie maken.
    function checkCredentials ($givenUsername = "", $givenPassword = "")
    {
        $this->passwordMd5 = md5($givenPassword);
        $this->username = $givenUsername;
        
        // kill bestaande sessie
        $_SESSION['login_'. $this->table] = "";
        
        $query = "SELECT id FROM ". $this->table ." WHERE username = '". $this->givenUsername ."' AND password = '". $this->givenPasswordMd5 ."'";
        $sql = mysql_query($query);

        if (mysql_num_rows($sql) == 0)  
        {
            header("location:".$this->loginURL);
        }
        else
        {
            $row = mysql_fetch_assoc($sql);
            $this->matchedId = $row['id'];
            $_SESSION['login_'. $this->table] = $this->matchedId;
            return $this->matchedId;
        }
    
    }
    
    // dit wordt geïnitialiseerd boven elke pagina: kijken of er een sessie bestaat en zo nee naar loginpagina doorsturen.
    function checkLoggedIn ()
    {
        $query = "SELECT name FROM ". $this->table ." WHERE id = ". $_SESSION['login_'. $this->table] ." LIMIT 1";
        $sql = mysql_query($query);
        
        if (mysql_num_rows($sql) == 0)
        {
            // terugsturen naar loginURL
            header("location:".$this->loginURL);
        }
        else
        {
            return true;
        }
    }
}


Wordt zo geïnitialiseerd:

PHP:
1
2
3
4
5
6
7
8
9
$auth = new Authentication();
$auth->setTable("test");
$auth->setLoginURL("http://www.foo.com/");

// voor nieuwe login:
$auth->checkCredentials($_GET['user'], $_GET['pass']);

// boven elke pagina:
$auth->checkLoggedIn();

[ Voor 9% gewijzigd door oscarvdb op 18-12-2005 17:52 ]

... he's gone.


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Je geeft je class nu veel te veel verantwoordelijkheid. Je mengt gegevens van een gebruiker, de tabel en database gegevens en voegt ook logica toe voor het doorsturen van een gebruiker. Beter is om dat allemaal los te houden. Ik zal eens kijken wat ik er van kan maken.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • oscarvdb
  • Registratie: December 2001
  • Laatst online: 20-05 09:45

oscarvdb

and like that...

Topicstarter
Michali schreef op zondag 18 december 2005 @ 18:07:
Je geeft je class nu veel te veel verantwoordelijkheid. Je mengt gegevens van een gebruiker, de tabel en database gegevens en voegt ook logica toe voor het doorsturen van een gebruiker. Beter is om dat allemaal los te houden. Ik zal eens kijken wat ik er van kan maken.
Super :).

... he's gone.


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Ik heb er een beetje mee zitten klooien en ben hier op uitgekomen:
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?

// config.php

define('USERS_TABLE', "users");
define('LOGIN_PAGE', "login.php");

// User.php

class User
{
    private $username;
    private $password;
    private $id;
    
    public function __construct($id = null, $username = null, $password = null)
    {
        $this->id = $id;
        $this->username = $username;
        $this->password = $password;
    }
    
    public function getID()
    {
        return $this->id;
    }
    
    // getters en setters
    
    public function isLoggedIn()
    {
        return !is_null($this->id);
    }
}

// UserRepository.php

class UserRepository
{
    public static function getByID($ID)
    {
        $query = "
            SELECT * 
            FROM " . USERS_TABLE . "
            WHERE id = " . (int)$ID;
        return self::getUserByQuery($query);
    }
    
    public static function getByUsernameAndPassword($username, $password)
    {
        $query = "
            SELECT *
            FROM " . USERS_TABLE . "
            WHERE username = '" . mysql_real_escape_string($username) . "'
            AND password = '" . md5($password) . "'
        ";
        return self::getUserByQuery($query);
    }
    
    private static function getUserByQuery($query)
    {
        $result = mysql_query($query);
        if ( !( $record = mysql_fetch_assoc($result) ) ) return null;
        return new User($record['id'], $record['username'], $record['password']);
    }
}

// UserSession.php

class UserSession
{
    public static function getCurrentUser()
    {
        if ( isset($_SESSION['current_user']) && !is_null($_SESSION['current_user']) )
        {
            $user = UserRepository::getByID($_SESSION['current_user']);
            if ( !is_null($user) ) return $user;
        }
        return new User();
    }
    
    public static function setCurrentUser(User $user)
    {
        $_SESSION['current_user'] = $user->getID();
    }
    
    public static function clear()
    {
        $_SESSION['current_user'] = null;
    }
}

// Security.php

class Security
{
    public static function checkUserRights()
    {
        $user = UserSession::getCurrentUser();
        if ( !$user->isLoggedIn() ) header("Location: " . LOGIN_PAGE);
    }
}

// Login.php

class Login
{
    private $username;
    private $password;
    
    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }
    
    public function execute()
    {
        $user = UserRepository::getByUsernameAndPassword($this->username, $this->password);
        if ( is_null($user) )
        {
            UserSession::clear();
        }
        else 
        {
            UserSession::setCurrentUser($user);
        }
    }
}

?>

Zoals je ziet heb ik verschillende taken verdeeld over verschillende classes. Dat geeft al een veel beter overzicht van wat je intentie met het geheel is. Begrijp me niet verkeerd, het kan nog veel losser en dynamischer, maar dat lijkt me voorlopig even te veel informatie en bovendien voor een klein probleem veel te veel complexiteit (in princiepe is dit al behoorlijk uitgebreid, maar zo kun je wel redelijk goed zien hoe je taken verdeelt over classes). Ik heb even veel gebruik gemaakt van statische methodes, omdat de classes toch stateless zijn, en ik nu niet van polymorphisch (zoek maar op op Google) gedrag gebruik maak, maakt dat niet zo veel uit. Als je echt de implementatie van je interface los wilt koppelen, dan moet je daar niet mee werken. Mischien ga ik een beetje ver in mijn uitleg, anders moet je maar om opheldering vragen.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Ik snap de scheiding in 3 functies van je UserRepository niet. Welke taak heeft welke functie? Je opdeling komt niet echt logisch over bij mij, ik had hier 2 functies van gemaakt met wat copy/pasta werk.
Verder vind ik je implementatie met heel veel class::function() niet echt netjes. Ik had hier eerder met singleton objecten gewerkt. Zeker als uitleg hoe het 'goed' moet aan iemand die nog nooit OOD heeft gewerkt :)

@TS: zodra je dit aan het werk hebt, ga dan eens kijken hoe OOD werkt. Probeer die lange post van mij eens door te worstelen, en wat diagrammetjes te maken voor wat 'simpele' situaties. Ik kan je wel wat opdrachten met uitwerkingen geven om mee te oefenen. Tipje: google kan die vakcode ook vinden ;)
Een goed onderhoudbaar systeem staat of valt bij een goed OOD ontwerp. Als je een slecht OOD ontwerp hebt, kan je beter functioneel werken :)

Acties:
  • 0 Henk 'm!

  • oscarvdb
  • Registratie: December 2001
  • Laatst online: 20-05 09:45

oscarvdb

and like that...

Topicstarter
Bedankt Michali en MBV, zodra ik tijd heb ga ik er goed naar kijken.

Nog een vraagje over de syntax; self::getUserByQuery(), betekent dat gewoon dat de methode getUserByQuery in de "eigen" klasse moet worden uitgevoerd?

Ik nam aan dat OOD stond voor "object orientated development", als synoniem voor OOP. Blijkt dat het Design is. :) Zal d'r es naar kijken.

Het ziet er allemaal uit als een flink ingewikkeld wereldje :P.

[ Voor 5% gewijzigd door oscarvdb op 18-12-2005 21:57 ]

... he's gone.


Acties:
  • 0 Henk 'm!

  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
Nog een vraagje over de syntax; self::getUserByQuery(), betekent dat gewoon dat de methode getUserByQuery in de "eigen" klasse moet worden uitgevoerd?
Inderdaad. self wordt gebruikt om te refereren naar de huidige klasse, $this naar het huidige object ($this is dus niet beschikbaar in een static function).

If you can't beat them, try harder


Acties:
  • 0 Henk 'm!

  • flashin
  • Registratie: Augustus 2002
  • Laatst online: 17-12-2023
Je geeft je class nu veel te veel verantwoordelijkheid. Je mengt gegevens van een gebruiker, de tabel en database gegevens en voegt ook logica toe voor het doorsturen van een gebruiker. Beter is om dat allemaal los te houden. Ik zal eens kijken wat ik er van kan maken.
Los houden is vaak wel duidelijker, maar ik vind persoonlijk jouw verdeling al wat ver gaan voor zoiets kleins. Zeker met het vele gebruik van static methods wordt het niet in 1x duidelijker.

Daarnaast denk ik dat je eerst met je DAL (Data Abstraction Layer) moet beginnen voordat je je data ook maar aan raakt :P

Maar voor de rest klopt dat voorbeeld wel natuurlijk :)

[ Voor 11% gewijzigd door flashin op 18-12-2005 22:58 ]


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
MBV schreef op zondag 18 december 2005 @ 21:09:
Ik snap de scheiding in 3 functies van je UserRepository niet. Welke taak heeft welke functie? Je opdeling komt niet echt logisch over bij mij, ik had hier 2 functies van gemaakt met wat copy/pasta werk.
Verder vind ik je implementatie met heel veel class::function() niet echt netjes. Ik had hier eerder met singleton objecten gewerkt. Zeker als uitleg hoe het 'goed' moet aan iemand die nog nooit OOD heeft gewerkt :)
Waarom vind je een Singleton een nettere oplossing? De eisen voor een Singleton zijn iig niet te bespeuren hier. Als een class geen state heeft kun je er beter geen Singleton van maken. Een Singleton is bedoeld (en alleen daarvoor) om er zeker van te zijn dat je van een class niet meerdere instances kunt maken en dat je overal toegang tot dezelfde enkele instance hebt. Zoiets is vaak ook alleen een vereiste als een bepaalde class een state heeft die op meerdere plaatsen toegankelijk moet zijn en eventueel gewijzigd moet kunnen worden. Als dat geen vereiste is, dan is een Singleton gewoon een verkeerde keuze. Het Singleton design pattern wordt al zo veel misbruikt, laten we het niet hier gaan doen. De classes, met statische functies, die ik presenteerde zijn pure Utility of Service classes. Dan is een statische functie echt helemaal geen verkeerde oplossing. Dergelijke classes hebben geen state, dus een statische functie voldoet dan wel. Een Singleton is iets wat je iig vrij weinig nodig zult hebben.

En zoals ik al zei, mogt je wel polymorphisch gedrag nodig hebben, dan is het idd soms geen goede keuze. Echter, kun je achter een class met statische functie wel gewoon delegaten naar een bepaalde interface. Die interface kun je dan laten implementeren door wat je wilt en de instance dan bijvoorbeeld met behulp van een factory aan laten maken. Dus een statische functie hoeft in princiepe ook helemaal geen belemmering te zijn voor polymorphisch gedrag. Als een class echter als parameter ergens aan mee moet worden gegeven of als je hem via een functie ergens van wilt verkrijgen, dan gaat dat niet met statische functies. Een losse interface (of eventueel een abstracte base class) en een implementatie is dan beter.

Laten we het iig verder niet over Singletons hebben en daarbij netjes in dezelfde zin verwerken, want dat gaat vaak helemaal niet goed samen.

Nog even over die functies. getByID verkrijgt een User object aan de hand van zijn ID. getByUsernameAndPassword lijkt me dan ook duidelijk. getUserByQuery is gewoon een interne functie die van een query een User object maakt. Ik geef hiermee niet aan dat dit een bijzonder net ontwerp is. Voor de eisen is het iig even voldoende, het ging er meer om om te laten zien hoe je een nette verdeling maakt met classes. Als je een wat uigebreider voorbeeld wilt, wel netjes met interfaces, factories ed. dan moet je maar vragen, dan tik ik nog wel een stukje.
@TS: zodra je dit aan het werk hebt, ga dan eens kijken hoe OOD werkt. Probeer die lange post van mij eens door te worstelen, en wat diagrammetjes te maken voor wat 'simpele' situaties. Ik kan je wel wat opdrachten met uitwerkingen geven om mee te oefenen. Tipje: google kan die vakcode ook vinden ;)
Een goed onderhoudbaar systeem staat of valt bij een goed OOD ontwerp. Als je een slecht OOD ontwerp hebt, kan je beter functioneel werken :)
Eens. Om echt OO goed onder de knie te krijgen kan ik je alleen maar een boek aanraden. Dat is iig iets wat je echt nodig hebt. Goede boeken zijn Design Patterns Explained, Applying UML & Patterns en Agile Software Development (al zou ik die laatste laten voor wat het is als je de eerste 2 nog niet gelezen hebt).

[ Voor 18% gewijzigd door Michali op 19-12-2005 00:05 ]

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

Verwijderd

[offtopic]
Zelf vind ik het ook lastig om te bepalen hoe je OOP objecten moet indelen. Ik ben dan ook opzoek naar online materiaal waarin duidelijk van begin tot eind een applicatie wordt gebouwd, zodat het voor mij duidelijk is waarom men bepaalde keuzes maakt. Weet iemand wellicht zoiets?

Acties:
  • 0 Henk 'm!

  • Sybr_E-N
  • Registratie: December 2001
  • Laatst online: 12:54
Verwijderd schreef op maandag 19 december 2005 @ 20:31:
[offtopic]
Zelf vind ik het ook lastig om te bepalen hoe je OOP objecten moet indelen. Ik ben dan ook opzoek naar online materiaal waarin duidelijk van begin tot eind een applicatie wordt gebouwd, zodat het voor mij duidelijk is waarom men bepaalde keuzes maakt. Weet iemand wellicht zoiets?
offtopic:
Wat je iig zou moeten doen is het boeken-topic eens doornemen. Aan de hand van de diverse reviews van de boeken, kun je een goede keus maken om bepaalde boeken aan te schaffen.

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Kijk eens hier. Dat zijn imo princiepes die erg belangrijk zijn. Ze worden ook allemaal besproken in het boek Agile Software Development.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

@TS: ik weet nog wel wat duidelijke slides over OOP met blaffende honden (ja die ene leraar op de THR ;)) en OOD design patterns op internet te staan. Geef maar een gil als je de URL's wilt weten.

@Michali: ik zou de singleton UserMgr (=UserRepository) en het gewone object MysqlDB maken (of uit een standaard library halen). UserMgr geeft vervolgens de User objecten terug, zoals jij ook doet, met gebruik van het MysqlDB object. Misschien zou ik die 2 laten samensmelten voor deze beperkte opzet.
Session zou ik (in de basis) staan, maar Security en Login zou ik een andere opzet geven. Eigenlijk vind ik login te weinig doen om er een aparte klasse voor te maken: hij roept alleen een functie aan op een andere klasse. Nu geen goed tijdstip om over na te denken, eerst eens even slapen :).

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Ik heb van die login een aparte class gemaakt omdat het zo erg handig is om vanaf verschillende plaatsen te kunnen inloggen. Je hoeft je dan ook niet meer druk te maken over de interne werking van het inloggen, je hoeft alleen zo'n object te instantieëren en je bent klaar.

Wat ik zelf altijd doe is een interface defineren voor repositories in de domain layer en een Registry class maken waarvan ik de implementaties kan krijgen. Deze controleert ook zelf de instances. In het begin van het uitvoeren van een script (de main() zeg maar :P) voed ik de Registry dan met de juiste factories om de juiste repositories te kunnen bouwen. Vaak is dat uiteraard eentje die een set repositories aanmaakt die alles in de database opslaat, maar het kunnen dan ook gemakkelijk stubs of mock objects zijn. Voor iets simpels als dit is dat onnodig, mijn voorbeeld is ook zeker overdreven complex, maar het is een voorbeeld en daar mag je je wel een beetje in uitsloven. Het ging er immers om hoe je functionaliteit verdeeld over verschillende classes.

Ik hoop dat de TS er ook iets van leert. Je hebt iig genoeg keywords om op te zoeken lijkt me. ;)

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Aan het begin van de main() ;) haal ik de objecten weer uit de sessie :P. Scheelt weer tijd als daar nogal veel inzit :)

En ik denk niet dat de TS erg veel van die 2e alinea snapt trouwens... erg veel jargon IMHO. Aangezien ik er eigenlijk al weer een poosje uit ben (op de TU/e krijg je alleen maar 'praten over' modellen ipv modellen maken :P) kost het mij ook moeite. Als de TS je intended audience was, zou ik hem even herschrijven :)

[ Voor 58% gewijzigd door MBV op 20-12-2005 10:51 ]


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
De TS wat idd niet echt mijn intended audience. Achter veel van die woorden zit idd ook een redelijke leer periode, dus als je ergens uitleg voor wilt moet je het maar vragen.

@TS: Sorry daarvoor, maar je hebt zo wel genoeg woorden om iets over op te zoeken lijkt me. Daar leer je ook al een hoop van.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • oscarvdb
  • Registratie: December 2001
  • Laatst online: 20-05 09:45

oscarvdb

and like that...

Topicstarter
MBV schreef op dinsdag 20 december 2005 @ 00:27:
@TS: ik weet nog wel wat duidelijke slides over OOP met blaffende honden (ja die ene leraar op de THR ;)) en OOD design patterns op internet te staan. Geef maar een gil als je de URL's wilt weten.
* oscarvdb gilt :)

... he's gone.


Acties:
  • 0 Henk 'm!

Verwijderd

Zelf vind ik het altijd veel fijner om één klasse die de core moet voorstellen, en daar zitten dan nog een aantal libs aan zoals mysql, user en template. De user heeft wél een directe aansluiting met de mysql klasse en template klasse voor de query's en het formulier + afhandelen van errors.

Wat zijn de voordelen om een autorisatie klasse op te splitsen in een aantal klasses?
Kan me niet voorstellen dat dit sneller is, over overzichtelijker?

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Geef eens een voorbeeld van je dan allemaal in je authorisatie class zet? Belangrijk is dat een class 1 reden voor bestaan heeft en zich zo min mogelijk (liefst niet) met andere zaken bezig houdt. Als een class 2 primaire taken heeft, dan is het beter om dat te splitsen.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

check maar je inbox :) 'k ga de linkjes niet publiek maken, beetje lullig voor de betreffende leraren :)
edit:
Van een mag het: OOP in C++, maar de concepten zijn redelijk generiek, door Harry Broeders: http://bd.thrijswijk.nl/syso1/index.htm
De rest ga ik niet eens vragen, omdat ik het dan ook moet hosten :P
Verwijderd schreef op woensdag 21 december 2005 @ 17:16:
Zelf vind ik het altijd veel fijner om één klasse die de core moet voorstellen, en daar zitten dan nog een aantal libs aan zoals mysql, user en template. De user heeft wél een directe aansluiting met de mysql klasse en template klasse voor de query's en het formulier + afhandelen van errors.

Wat zijn de voordelen om een autorisatie klasse op te splitsen in een aantal klasses?
Kan me niet voorstellen dat dit sneller is, over overzichtelijker?
Ligt aan de situatie. Bij deze situatie zou ik dat zelf niet doen. Toen ik bezig was mijn nieuwe website op te zetten heb ik het wel gedaan: een klasse picturedir, die alle andere klasses voor de betreffende directory aan kan maken. de functie getPictureIterator gaf een geïnitialiseerde PictureIterator terug. Voordeel van de centrale klasse was dat er geen vergissingen gemaakt kunnen worden bij de constructie van de objecten.

@Michali: daar zat ik ook al mee te worstelen met de website waar ik het hierboven over heb ;) Security zou een soort van manager worden, aan wie gevraagd kan worden of een actie uitgevoerd kan worden. zou dus de functie mayOpen($user, $page) kunnen bevatten. Maar daar moet ik nog eens goed over nadenken. Eerst de rest van mijn site laten werken :) en de directory "hidden" hardcoded weglaten zonder login O-)
Werkt trouwens heel handig: /onderwerp/hidden/ mag niemand zien, maar /onderwerp/hidden/trouwerij/ mag wel door iedereen bekeken worden. Je geeft een deeplink aan degenen die het mogen zien, en je bent klaar :). En ik weet je te vinden als mijn log nu ineens vol komt te staan met trial-and-error pogingen om mijn boom te doorgronden :P. Staat toch niks in wat echt spannend is, alleen een paar uitjes waarvan de onderwerpen niet publiek online willen staan 8)7

[ Voor 95% gewijzigd door MBV op 22-12-2005 11:35 ]

Pagina: 1