Ankündigung

Einklappen
Keine Ankündigung bisher.

Benutzer-Model

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Benutzer-Model

    Hallo Zusammen,

    ich bin derzeit an einem sehr großen Projekt und muss mir daher sehr viele Gedanken über die Struktur machen. Natürlich ist das ganze nicht so einfach wie die meisten denken und von daher richtet sich mein größtes Problem an die Benutzerverwaltung.

    Ein Benutzer hat immer folgende Daten:
    ID* (UNIQUE, PK)
    E-Mailadresse* (UNIQUE)
    Passwort* (MD5)
    Vorname*
    Nachname*
    Status*
    Adresse
    Telefonnummer
    Geburtstag
    Punkte
    Foto

    Alle mit * gekennzeichneten Felder sind immer hinterlegt. Neben diesen Daten müssen nun natürlich auch noch beziehungen etabliert werden. Das heißt in erster Linie, dass jeder Benutzer Rechte und Freunde sowie eigene Alben haben kann die natürlich auch im Benutzer-Verwaltungs-System etabliert werden möchten. Desweiteren haben Benutzer Punkte, die Sie für diverse Aktionen auf dem Portal erhalten. Durch die Punkte, können die Benutzer sich dann virtuelle Goodies kaufen. Ein weiterer Punkt, was alle Benutzer haben ist das Nachrichtensystem, wo sie ausschließlich mit ihren eigenen Freunden schreiben können.

    Das System braucht also folgende Bausteine (Übersicht):
    Rechte
    Freunde
    Alben
    Punkte
    Nachrichtensystem
    Standard-Funktionen (Benutzer auslesen, bearbeiten, löschen usw.)

    Da ich keine Lust habe, das Projekt direkt am Anfang zu "versauen" möchte ich jetzt Rat von ein paar erfahrenen PHP-Nutzern, die vielleicht bereits ein derartiges Projekt geschrieben haben.

    Ich gehe mal näher auf die einzelnen Module ein:

    Rechte:
    Wie bereits erwähnt, hat jeder Benutzer diverse Rechte, die sich aus einer Gruppe ergeben. Das heißt konkret, dass jeder Benutzer mehrere Gruppen haben kann und die Rechte sich dadurch ergänzen. Das heißt wenn ein Mitglied die Gruppen Mitglieder sowie Moderatoren hat erhält er alle Rechte aus den jeweiligen Gruppen.

    Freunde:
    Jeder Benutzer kann sich seinen eigenen Freundesstamm aufbauen. Da eine einfache N:M Beziehung hier meiner Meinung nach fehl am Platz wäre, wäre es meiner Meinung nach optimal, dass jede Beziehung zwei mal in der Datenbank geführt wird, dass es einfacher zum auslesen ist. Es gibt in der Tabelle einmal das Feld user_id und einmal das Feld friend_id - da man nun nicht von beiden Seiten ohne weiteres die Freunde herausbekommt, ist es meiner Meinung nach ratsam, die Einträge in beide Seiten zu führen.

    Alben:
    Benutzer können verschiedene Alben haben in denen es Funktionen gibt, die ich hier leider aus mehreren Gründen nicht nennen darf.

    Punkte:
    Für diverse Aktionen auf dem Portal erhalten Benutzer Punkte. Da ich einen Missbrauch verhindern möchte, will ich in der Datenbank einen Log haben, wo alle Buchungen festgehalten werden. Einmal in der Nacht, werden alle Benutzer kontrolliert und die Punkte geupdatet sofern sie nicht stimmen.

    Nachrichtensystem:
    Einer der größten Punkte ist wohl das Nachrichtensystem - wobei ich hier schon eine konkrete Vorstellung habe, wie das ganze aussehen soll. Da ich keinen doppelten Text haben möchte, soll der Text einer Nachricht als UNIQUE in einer seperaten Datenbank gespeichert werden. Desweiteren soll jeder Benutzer seine Nachricht in einen Ordner verschieben können. Das heißt zusätzlich zum Nachrichtensystem benötigt man im Nachrichtensystem folgende Optionen: Nachricht schreiben, löschen, verschieben; Ordner erstellen, löschen, bearbeiten; Postausgang löschen.

    Das ganze Benutzerverwaltungssystem soll nach allen Regeln des OOP erstellt werden. Effektiv heißt das, dass ich mit vielen Interfaces sowie Abstrakten Klassen arbeiten werde.

    Ich bin derzeit an einem UML-Diagramm dran, muss aber sagen, dass ich nicht so sehr mit den Funktionen eines Diagramms vertraut bin.

    Wie mache ich das am schlausten. Ich möchte jetzt nicht darum bitten, dass mir jemand ein UML erstellt oder eine derartige Arbeit macht, allerdings geht es mir rein um die Logik, die ich beachten sollte bei einem derartigen Benutzertool.

    Gruß,

    Marc
    true||false - www.trueorfalse.de - Rund um Software Entwicklung


  • #2
    Hallo,

    zeige uns doch einmal, was du bereits hast. Lade ein UML-Diagramm irgendwo hoch und verlinke es. Dann können wir dir auch bessere helfen.
    Zum Thema Benutzerverwaltung gab es hier schonmal einen Thread, den solltest du dir auf jeden Fall durchlesen, um dein System zu verfeinern und auch mit Rollen zu ergänzen.
    Refining Linux: “Performing Push Backups – Part 1: rdiff-backup

    Kommentar


    • #3
      Solch ein Nachrichtensystem habe ich mal geschrieben. Dazu habe ich diese zwei tabellen:

      Ordner:
      PHP-Code:
      CREATE TABLE IF NOT EXISTS `_post_ordner` (
        `
      lfdint(10unsigned NOT NULL AUTO_INCREMENT COMMENT 'Zeilennummer',
        `
      useridint(10unsigned NOT NULL DEFAULT '0' COMMENT 'user-lfd',
        `
      namevarchar(16NOT NULL DEFAULT '',
        
      PRIMARY KEY (`lfd`),
        
      KEY `userid` (`userid`)
      ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Ordner-Verwaltung Nachrichtensystem' AUTO_INCREMENT=105 ;

      --
      -- 
      Daten für Tabelle `post_ordner`
      --

      INSERT INTO `_post_ordner` (`lfd`, `userid`, `name`) VALUES(10'Posteingang');
      INSERT INTO `_post_ordner` (`lfd`, `userid`, `name`) VALUES(20'Postausgang');
      INSERT INTO `_post_ordner` (`lfd`, `userid`, `name`) VALUES(30'gesendete');
      INSERT INTO `_post_ordner` (`lfd`, `userid`, `name`) VALUES(40'gelöschte');
      INSERT INTO `_post_ordner` (`lfd`, `userid`, `name`) VALUES(1001'Privat');
      INSERT INTO `_post_ordner` (`lfd`, `userid`, `name`) VALUES(1011'Beruf');
      INSERT INTO `_post_ordner` (`lfd`, `userid`, `name`) VALUES(1021'Schule'); 
      Die ersten 4 Ordner sind die bekanten System-Ordner, die jeder hat. Im Script wird der Ordner "gelöschte" dann mit der Nummer 4 angesprochen.

      Hier im Beispiel hat der User mit der ID=1 sich drei eigene Ordner angelegt: Privat, Beruf und Schule. Im Script weden die Ordner mit den Nummern 100,101 und 102 verwaltet.

      Post:
      PHP-Code:
      CREATE TABLE IF NOT EXISTS `_post` (
        `
      lfdint(10unsigned NOT NULL AUTO_INCREMENT COMMENT 'Zeilennummer',
        `
      betreffvarchar(30NOT NULL DEFAULT '',
        `
      nachrichttext NOT NULL COMMENT 'Nachrichtentext',
        `
      vonint(10unsigned NOT NULL DEFAULT '0' COMMENT 'user-lfd',
        `
      von_ordnerint(10unsigned NOT NULL DEFAULT '0' COMMENT 'ordner-lfd',
        `
      anint(10unsigned NOT NULL DEFAULT '0' COMMENT 'user-lfd',
        `
      an_ordnerint(10unsigned NOT NULL DEFAULT '0' COMMENT 'ordner-lfd',
        `
      gelesenenum('nein','ja'NOT NULL DEFAULT 'nein',
        `
      sendezeitdatetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Nachriht abgesendet Datum/Zeit',
        
      PRIMARY KEY (`lfd`),
        
      KEY `von` (`von`),
        
      KEY `an` (`an`)
      ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=40176 
      Bei einer neuen nachricht werden zunächst die Ordner von=2 und an=1 eingetragen. Die User können das dann in die eigenen privaten Ordner 'verschieben', wobei halt die existierenden Ordnernummern eingetragen werden.

      Den nachrichtentext würde ich nicht auf Unique stellen. Leute könnten auf eine Nachricht mit "Vielen Dank, bis dann!" antworten.
      PHP-Code:
      if ($var != 0) {
        
      $var 0;

      Kommentar


      • #4
        Zum Thema Rechtesystem kannst du dir eine Lösung vielleicht aus dem ACL des ZF holen:
        Zend Framework: Documentation
        "Mein Name ist Lohse, ich kaufe hier ein."

        Kommentar


        • #5
          Danke bereits für eure Mühen. Das UML-Diagramm lade ich natürlich morgen im laufe des Vormittages hoch.

          Rechtesystem:
          Das Rechtesystem habe ich bereits zum Teil abgeschlossen. Es funktioniert über 4 Tabellen und wird dauerhaft im Cache gehalten, sofern sich nichts daran ändert.

          user_rights: Beinhaltet alle Rechte inkl. Beschreibung.
          user_groups: Beinhaltet alle Gruppen.
          user_group_rights: Beinhaltet alle Rechte, die die jeweilige Gruppe besitzt (N:M).
          user_group_joins: Beinhaltet die Beziehung zwischen Benutzer und Gruppe.

          Die Struktur habe ich mir schon überlegt an Acl anzulehnen bzw. sogar in Acl zu importieren.

          Nachrichtensystem:
          Danke für deine Mühen, allerdings glaube ich nicht, dass ein derartiges System meinen Anforderungen ausreicht. Zunächsteinmal fehlen bei dieser Variante FKs, die mir sehr wichtig sind, da ich direkte bezüge benötige. Desweiteren gibt es einige Funktionen, die ich mit FKs verwenden kann (bspw. löschen durch eine FK-Beziehung etc.).

          Desweiteren würde bei deiner Variante der Text doppelt in der Datenbank stehen, sofern ein Benutzer mehrere Nachrichten mit dem selben Text an verschiedene Benutzer übersendet.

          Desweiteren hatte ich bei messages an eine derartigen aufbau gedacht:

          messages: Beinhaltet alle Nachrichten (Text ausgeschlossen) - direkte Beziehung zwischen N:M zu Sender und Versender.
          message_folders: Beinhaltet alle Ordner mit einer N:M Beziehung zum Benutzer (Ersteller).
          message_folder_joins: Beinhaltet die Beziehung zwischen Nachricht und Ordner - gibt die Möglichkeit eine Nachricht in mehrere Ordner zu kopieren.
          message_text: Beinhaltet die Texte für alle Nachrichten mit N:M Bezug auf "messages".

          Standardmäßig werden 2 Folder erstellt bei einer Registrierung:

          - Posteingang
          - Postausgang

          Beide können durch ein Flag in der Datenbank nicht entfernt werden. Die Folder werden dann verwendet um die Nachrichten anzuzeigen, die der jeweilige Benutzer erhalten und versendet hat.

          UPDATE:
          Ich findet das Thema nicht - erinnerst du dich ggf. an den Titel?
          true||false - www.trueorfalse.de - Rund um Software Entwicklung

          Kommentar


          • #6
            http://www.php.de/software-design/50...erwaltung.html
            Refining Linux: “Performing Push Backups – Part 1: rdiff-backup

            Kommentar


            • #7
              Sehe ich genauso, das Thema wurde IMHO schon zur Genüge diskutiert.
              Viele Grüße,
              Dr.E.

              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
              1. Think about software design before you start to write code!
              2. Discuss and review it together with experts!
              3. Choose good tools (-> Adventure PHP Framework (APF))!
              4. Write clean and reusable software only!
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

              Kommentar


              • #8
                Was sind FKs?
                PHP-Code:
                if ($var != 0) {
                  
                $var 0;

                Kommentar


                • #9
                  Fremd-Schlüssel. Kommt von "foreign keys". Dies bezeichnet die Speicherung eines PK-Wertes einer Tabelle in einer anderen zur Referenzierung eines Datensatzes.
                  Viele Grüße,
                  Dr.E.

                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  1. Think about software design before you start to write code!
                  2. Discuss and review it together with experts!
                  3. Choose good tools (-> Adventure PHP Framework (APF))!
                  4. Write clean and reusable software only!
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                  Kommentar


                  • #10
                    Zur Ergänzung: PK == Primary Key.
                    Refining Linux: “Performing Push Backups – Part 1: rdiff-backup

                    Kommentar


                    • #11
                      Zitat von dr.e. Beitrag anzeigen
                      Sehe ich genauso, das Thema wurde IMHO schon zur Genüge diskutiert.
                      Das Rechtesystem ist auch nicht direkt das Problem. Mein Problem befasst sich in erster Linie damit, dass ich nicht weis wo ich direkt anfangen soll. Es wäre gut eine Klasse zu haben, die bspw. über die ID eines Benutzers alle Daten ausliest. Das wäre praktisch zum Iterieren.

                      Beispiel:
                      PHP-Code:
                      <?php
                      $ids 
                      = array(13892092);
                      foreach (
                      $ids as $id) {
                      $user[$id] = new DP_User($id);
                      }

                      $user[8]->getRights(); // Liefert alle Rechte.
                      $user[8]->forename// Liefert den Vornamen.
                      $user[8]->getGroups(); // Liefert alle Gruppen. 
                      $user[8]->created// Liefert das Erstellungsdatum.
                      // etc...
                      Desweiteren möchte ich natürlich auch das Thema Session-Management ansprechen, welches auch eine große Rolle spielt und ich oben vergessen habe.

                      Wäre es Sinnvoll die o.g. Lösung umzusetzten und zusätzliche Abstrakte Klassen zu erstellen, die sich um das auslesen von Rechten, Gruppen und andere Daten kümmern?

                      Gruß,

                      Marc
                      true||false - www.trueorfalse.de - Rund um Software Entwicklung

                      Kommentar


                      • #12
                        Anbei das UML-Diagramm für die Benutzerverwaltung.
                        Die Komponennten habe ich derzeit noch nicht im Model integriert, da ich mir noch nicht 100 % sicher bin bei dieser Variante.

                        Ich habe vor, dass ich über eine Klasse "User" alle Daten eines Benutzers herauszubekommen desweiteren möchte ich, dass die o.g. Klasse auch Login und Logout übernimmt.

                        Ein aufruf sollte dann bspw. so aussehen:

                        PHP-Code:
                        <?php
                        $groups 
                        User::identifier(1)->getGroups()->asArray();
                        foreach (
                        $groups as $group) {
                        // something
                        }

                        // Rights
                        User::emailaddress('test@test.de')->getRights()->hasRight('write_news');

                        // Login or logout.
                        User::login('test@test.de''test');
                        User::logout();
                        Gruß,

                        Marc
                        Angehängte Dateien
                        true||false - www.trueorfalse.de - Rund um Software Entwicklung

                        Kommentar


                        • #13
                          Das oben publizierte UML-Diagramm ist leider noch sehr undurchdacht. Anbei findet Ihr die neue Version des User-Objekts. Allerdings fehlen die kompletten komponenten, da ich zunächst wissen will, ob dieser Aufbau rentabel ist.

                          Ich selbst finde, dass dies eine gute Lösung wäre - kann aber auch sein, dass ich was besser machen kann. Und genau um das bitte ich euch: Kritisiert den Aufbau, sofern Ihr es konstruktiv könnt und ggf. Tipps abgeben könnt. Äußert Bedenken und Anregungen. Ich bedanke mich hiermit schon einmal im Voraus.



                          PHP-Code:
                          <?php
                          interface User_Interface
                          {
                              
                              public function 
                          __get($key);
                              public function 
                          getRights();
                              public function 
                          getMessages();
                              public function 
                          getMessageFolders();
                              public function 
                          getEntrys();
                              public function 
                          getAlbums();
                              public function 
                          getPoints();
                              public function 
                          getSession();
                              public function 
                          getEditor();
                              
                          }

                          abstract class 
                          User_Abstract implements User_Interface
                          {
                              
                              protected 
                          $_user = array();
                              
                              public function 
                          __get($key)
                              {
                                  return 
                          $this->_user[$key];
                              }
                              
                              public function 
                          getRights()
                              { }
                              
                              public function 
                          getMessages()
                              { }
                              
                              public function 
                          getMessageFolders()
                              { }
                              
                              public function 
                          getEntrys()
                              { }
                              
                              public function 
                          getAlbums()
                              { }
                              
                              public function 
                          getPoints()
                              { }
                              
                              public function 
                          getSession()
                              { }
                              
                              public function 
                          getEditor()
                              { }
                              
                          }

                          class 
                          User
                          {
                              
                              private static 
                          $_instances = array();
                              
                              public static function 
                          identifier($value)
                              {
                                  if (empty(
                          self::$_instances[__METHOD__][$value])) {
                                      
                          self::$_instances[__METHOD__][$value] = new User_Identifier($value);
                                  }
                                  return 
                          self::$_instances[__METHOD__][$value];
                              }
                              
                              public static function 
                          emailaddress($value)
                              {
                                  if (empty(
                          self::$_instances[__METHOD__][$value])) {
                                      
                          self::$_instances[__METHOD__][$value] = new User_Identifier($value);
                                  }
                                  return 
                          self::$_instances[__METHOD__][$value];
                              }
                              
                              private function 
                          __clone()
                              { }
                              
                          }

                          class 
                          User_Identifier extends User_Abstract
                          {
                              
                              public function 
                          __construct($identifier)
                              {
                                  if (
                          $this->_checkIdentifier($identifier)) {
                                      
                          $this->_initialize();
                                      return 
                          true;
                                  }
                                  return 
                          false;
                              }
                              
                              private function 
                          _checkIdentifier($identifier)
                              { }
                              
                              private function 
                          _initialize()
                              { }
                              
                          }

                          class 
                          User_Emailaddress extends User_Abstract
                          {
                              
                              public function 
                          __construct($emailadress)
                              {
                                  if (
                          $this->_checkEmailadress($emailadress)) {
                                      
                          $this->_initialize();
                                      return 
                          true;
                                  }
                                  return 
                          false;
                              }
                              
                              private function 
                          _checkEmailaddress($emailadress)
                              { }
                              
                              private function 
                          _initialize()
                              { }
                              
                          }
                          Angehängte Dateien
                          true||false - www.trueorfalse.de - Rund um Software Entwicklung

                          Kommentar


                          • #14
                            Nehmt euch doch einfach mal den von mir verlinkten Thread zu Herzen. Zwischen konkreten Klassen und Interfaces besteht IMHO übrigens keine Aggregationsbeziehung. Stattdessen wird das Interface von der konkreten Klasse implementiert.
                            Refining Linux: “Performing Push Backups – Part 1: rdiff-backup

                            Kommentar


                            • #15
                              Hier mal eine Zusammenfassung der Geposten UML aus dem link da sie in den 3 Seiten doch ein wenig untergehen.

                              Vom Adventure Framework:
                              Module - Usermanagement :: Adventure PHP Framework (APF)

                              Vom einen Forum User:
                              http://img93.imageshack.us/img93/372...ndiagraed2.jpg

                              Hier nochmal der Unterschied Rollen /Gruppen link
                              http://www.mwiesner.com/index.php/20...keine-gruppen/

                              Mfg Splasch

                              Kommentar

                              Lädt...
                              X