Pisząc swój pierwszy półprofesjonalny serwisik (czytaj: taki, który wyjdzie oficjalnie na świat ;) ) w Symfony, natknąłem się na problem administracji użytkownikami, którzy powinni należeć tylko i wyłącznie do jednej grupy.

Mamy sobie aplikację z użytkownikami zarządzanymi przez sfGuarda. Każdy użytkownik powinien należeć tylko do jednej z wybranych grup, zatem odmiennie od domyślnej konfiguracji sfGuarda, który zezwala na łączenie użytkownika z wieloma grupami (relacje m-n).

Można spróbować pisania metod setGroup(), która usunie poprzedni związek sfGuardUserGroup i utworzy nowy, ale to raczej obchodzenie problemu, sprawiające więcej problemów niż pożytku.

Proponowane przeze mnie rozwiązanie - skorzystać z pluginu sfPropelAlternativeSchemaPlugin, który pozwala na dokonywanie zmian w domyślnym schemacie pluginów.

Własne klasy sfGuardUser i sfGuardUserPeer

Na początku proponuję utworzyć dwa pliki pozwalające przeładować standardowe metody klas sfGuardUser oraz sfGuardUserPeer. Pozwoli to później łatwo rozbudować klasy bez konieczności nadpisywania plików z katalogu plugins/ - podczas aktualizacji pluginu te zostaną przywrócone do pierwotnej wersji.

Zatem w katalogu lib/model/ tworzymy nowy katalog sfGuardPlugin, a wewnątrz dwa pliki php o zawartości:

 
<?php
/**
 * sfGuardUser.php 
 */
class sfGuardUser extends PluginsfGuardUser
{       
 
}
 

oraz:

 
<?php
/**
 * sfGuardUserPeer.php 
 */
class sfGuardUserPeer extends PluginsfGuardUserPeer
{       
  public static function getOMClass()
  {
    return 'lib.model.sfGuardPlugin.sfGuardUser';
  }
}
 

W plikach będziemy mogli tworzyć nowe metody, bez obawy, że aktualizacja pluginu nadpisze nasze wypociny ;)

Zmiany schematu sfGuardUser

Wracamy do głównego tematu - zmiana działania grup w sfGuard. Pobieramy plugin sfPropelAlternativeSchemaPlugin:

 
cd plugins/
svn co http://svn.symfony-project.com/plugins/sfPropelAlternativeSchemaPlugin/
symfony cc
 

Plugin dostępny też jest przez standardowe symfony plugin-install, ale tam jest starsza wersja z błędami nie pozwalającymi korzystanie z pluginu pod systemem Windows.

Teraz można zabrać się za modyfikację schematu sfGuarda. W katalogu config/ tworzymy nowy plik o nazwie sfGuardPlugin_schema.custom.yml (tak wymaga plugin) i tam ustalamy nowy schemat:

 
propel:
  sf_guard_user:
    _attributes:    { phpName: sfGuardUser }
    id:             ~
    group_id:       { type: integer }
    firstname:      varchar(63)
    lastname:       varchar(63)
    email:          varchar(127)
    phone:          varchar(32)
    other:          varchar(255)
    _foreignKeys:
      -
        foreignTable: sf_guard_group
        onDelete:     setnull
        references:
          - { local: group_id, foreign: id }
 

Jak widać, dodałem tutaj kilka dodatkowych pól, przez co nie musimy tworzyć nowej tabeli z profilem użytkownika (standardowo: sf_guard_user_profile), bo wszystkie dodatkowe pola są dostępne bezpośrednio.

Najważniejszym polem dla nas jest group_id, wskazujące na grupę (sfGuardGroup), do której przypiszemy każdego usera. Dziwna struktura zaczynająca się od _foreignKeys: jest stosowana w nowo zainstalowanym pluginie, ale można używać poprzedniego sposobu definiowania kluczy zewnętrznych.

Po zapisaniu pliku i przebudowaniu modelu można już korzystać z nowej struktury sfGuarda.

Poprawienie czytania uprawnień grup

Jeszcze jedna ważna sprawa dla korzystających z systemu uprawnień dostępnych w sfGuardzie (sfGuardPermission):

Domyślnie, plugin sfGuard pozwala przypisać uprawnienia zarówno bezpośrednio do użytkownika (tabelą sfGuardUserPermission) oraz do każdej grupy (sfGuardGroupPermission), do której należy nasz user (co pobiera przez tabelę sfGuardUserGroup).

Po usunięciu naszego łącza pomiędzy sfGuardUser a sfGuardGroup, potrzebujemy poprawić metodę getGroups(), która to zwracała wszystkie grupy do których należy użytkownik.

Tutaj właśnie przyda nam się utworzona na początku klasa sfGuardUser, gdzie można dopisać własne metody lub przeładować już istniejące. W pliku sfGuardUser.php dodajemy funkcję:

 
<?php
/**
 * Poprawka getGroups, zwracająca w tablicy tylko 1 grupę
 */
public function getGroups()
{
        if (!$this->groups)
        {
                $this->groups = array();
                $group = $this->getGroup();
                if($group) $this->groups[$group->getName()] = $group;
        }
        return $this->groups;
}
 

Dzięki przeładowaniu metody, pobieranie uprawnień użytkownika z grupy wróci do normy, a my możemy się cieszyć jednogrupowymi użytkownikami ;)

Komentarze do wpisu "sfGuard - użytkownik należący tylko do jednej grupy":

Jeszcze nie ma żadnych komentarzy. Twój może być pierwszy.

Dodaj komentarz: