Erweiterung der fe_users mittels Extbase 1.3

Extbase liefert standardmäßig bereits eine Model-Klasse und die dazugehörige Repository-Klasse für die Tabelle fe_users mit, diese heißen Tx_Extbase_Domain_Model_FrontendUser (Model) und Tx_Extbase_Domain_Repository_FrontendUserRepository (Repository).

In der Model-Klasse befinden sich bereits wesentliche Getter- und Setter-Methods für die einzelnen Tabellenfelder der Tabelle fe_users.

Zunächst könnten wir meinen, dass es genügt sich bspw. in seinem Controller über folgenden Aufruf, einen bestimmten fe_user zu holen:

class Tx_MyExt_Controller_FrontendUserController extends Tx_Extbase_MVC_Controller_ActionController {
    
   /**
     *
     * @var Tx_Extbase_Domain_Repository_FrontendUserRepository 
     */
    protected $frontendUserRepository = NULL;

    /**
     *
     * @param Tx_Extbase_Domain_Repository_FrontendUserRepository $frontendUserRepository 
     */
    public function injectFrontendUserRepository(Tx_Extbase_Domain_Repository_FrontendUserRepository $frontendUserRepository) {
        $this->frontendUserRepository = $frontendUserRepository;
    }

    
    public function showExampleUserAction() {
           $frontendUser = $this->frontendUserRepository->findOneByUid(1);
           /* @var $frontendUser Tx_Extbase_Domain_Model_FrontendUser */
           $this->view->assign('frontendUser', $frontendUser);
           
    }
}

Leider werden wir zunächst feststellen, dass die Variable frontendUser NULL ist. Es sei denn, wir haben im Datensatz des fe_users den RecordType auf Tx_Extbase_Domain_Model_FrontendUser bereits definiert.

Denn dies ist notwendig, da Extbase über die eigens mitgelieferte TypoScript-Konfiguration (in der Datei ext_typoscript_setup.txt) das spezifische Mapping von Model zu Tabelle nur über den konkreten RecordType vornehmen kann.

config.tx_extbase {
	[...]
	persistence{
		classes {
			Tx_Extbase_Domain_Model_FrontendUser {
				mapping {
					tableName = fe_users
					recordType = Tx_Extbase_Domain_Model_FrontendUser
					columns {
						lockToDomain.mapOnProperty = lockToDomain
					}
				}
			}			
		}
	}
        [...]
}

Wenn wir jetzt den RecordType definiert haben, sollte unsere frontendUser-Variable nicht mehr NULL sein und wir können auf die von extbase vordefinierten Eigenschaften wie firstName zugreifen.

In der Regel reichen aber die vordefinierten Felder innerhalb der mitgelieferten Model-Klasse von extbase nicht aus.
Möchten wir also andere oder neue Felder ausgeben, müssen wir die bestehende Model-Klasse erweitern.

Nehmen wir an, dass wir ein boolesches Feld isSuperAdmin in unserer Tabelle fe_users ergänzt haben (TCA-Konfiguration ist ebenfalls korrekt erstellt), dann erweitern wir also die Model-Klasse Tx_Extbase_Domain_Model_FrontendUser bspw. folgendermaßen:

class Tx_MyExt_Domain_Model_FrontendUser extends Tx_Extbase_Domain_Model_FrontendUser {
    
    /**
     *
     * @var boolean     
     */ 
    protected $isSuperAdmin = FALSE;

    /**
     *
     * @return boolean $isSuperAdmin
     */
    public function getIsSuperAdmin() {
       return $this->isSuperAdmin;
    }
    
    /**
     *
     * @param boolean $isSuperAdmin
     */
    public function setIsSuperAdmin($isSuperAdmin) {
        $this->isSuperAdmin = $isSuperAdmin;
    }
}

Wir müssen im nächsten Schritt extbase beibringen, dass nicht mehr die Model-Klasse Tx_Extbase_Domain_Model_FrontendUser für das Mapping herangezogen wird, sondern unsere eigene Model-Klasse Tx_MyExt_Domain_Model_FrontendUser.

Dafür müssen wir zum einen im TS-Setup folgende Direktive aufnehmen:

config.tx_extbase {
	[...]
	persistence{
		classes {
			Tx_MyExt_Domain_Model_FrontendUser {
				mapping {
					tableName = fe_users
					recordType = Tx_Extbase_Domain_Model_FrontendUser
					columns {
						lockToDomain.mapOnProperty = lockToDomain
					}
				}
			}			
		}
	}
        [...]
}

und zum anderen eine eigene Repository-Klasse erstellen:

class Tx_MyExt_Domain_Repository_FrontendUserRepository extends Tx_Extbase_Domain_Repository_FrontendUserRepository {

}

Unseren Controller ändern wir dann folgendermaßen:

class Tx_MyExt_Controller_FrontendUserController extends Tx_Extbase_MVC_Controller_ActionController {
    
   /**
     *
     * @var Tx_MyExt_Domain_Repository_FrontendUserRepository 
     */
    protected $frontendUserRepository = NULL;

    /**
     *
     * @param Tx_MyExt_Domain_Repository_FrontendUserRepository $frontendUserRepository 
     */
    public function injectFrontendUserRepository(Tx_MyExt_Domain_Repository_FrontendUserRepository $frontendUserRepository) {
        $this->frontendUserRepository = $frontendUserRepository;
    }

    
    public function showExampleUserAction() {
           $frontendUser = $this->frontendUserRepository->findOneByUid(1);
           /* @var $frontendUser Tx_MyExt_Domain_Model_FrontendUser */
           $this->view->assign('frontendUser', $frontendUser);
           
    }
}

So sollte unserer Erweiterung nichts mehr im Wege stehen.

Erweiterung
Häufig kommt die Anforderung, dass wir immer den eingeloggten User auf unsere Model-Klasse „mappen“ wollen.
Am einfachsten ist sicherlich das folgende Beispiel:

class Tx_MyExt_Controller_FrontendUserController extends Tx_Extbase_MVC_Controller_ActionController {
    
   /**
     *
     * @var Tx_MyExt_Domain_Repository_FrontendUserRepository 
     */
    protected $frontendUserRepository = NULL;

    /**
     *
     * @param Tx_MyExt_Domain_Repository_FrontendUserRepository $frontendUserRepository 
     */
    public function injectFrontendUserRepository(Tx_MyExt_Domain_Repository_FrontendUserRepository $frontendUserRepository) {
        $this->frontendUserRepository = $frontendUserRepository;
    }

    
    public function showLoggedInUserAction() {
           $frontendUser = $this->frontendUserRepository->findOneByUid(intval($GLOBALS['TSFE']->fe_user->user['uid']));
           /* @var $frontendUser Tx_Extbase_Domain_Model_FrontendUser */
           $this->view->assign('frontendUser', $frontendUser);
           
    }
}

Hier nehmen wir allerdings keinerlei weitere Überprüfung vor. Nicht so gut. Zudem müssen wir diesen Aufruf für jede Action, in dem wir den eingeloggten User als gemapptes Objekt haben wollen, immer wieder erneut vornehmen.

Empfehlenswert wäre es also, sich eine Service-Klasse für die Zugriffskontrolle zu schreiben und in der InitializeAction des Controllers das Mapping für jede Action „vorwegzunehmen“.

Zunächst die einfache Service-Klasse:

class Tx_MyExt_Service_AccessControlService implements t3lib_Singleton {

    /**
     * Do we have a logged in feuser
     * @return boolean
     */
    public function hasLoggedInFrontendUser() {
        return $GLOBALS['TSFE']->loginUser === 1 ? TRUE : FALSE;
    }

    /**
     * Get the uid of the current feuser
     * @return mixed
     */
    public function getFrontendUserUid() {
        if ($this->hasLoggedInFrontendUser() && !empty($GLOBALS['TSFE']->fe_user->user['uid'])) {
            return intval($GLOBALS['TSFE']->fe_user->user['uid']);
        }
        return NULL;
    }
    
    /**
     * @param Tx_Extbase_Domain_Model_FrontendUser $frontendUser
     * @return boolean
     */
    public function isAccessAllowed(Tx_Extbase_Domain_Model_FrontendUser $frontendUser) {
      return $this->getFrontendUserUid() === $frontendUser->getUid() ? TRUE : FALSE;
    }
}

Dann schreiben wir unseren erweiterten Controller:

class Tx_MyExt_Controller_FrontendUserController extends Tx_Extbase_MVC_Controller_ActionController {
    
    /**
     *
     * @var Tx_MyExt_Service_AccessControlService 
     */
    protected $accessControlService;
  
    /**
     *
     * @param Tx_MyExt_Service_AccessControlService $accessControlService
     */
    public function injectAccessControlService(Tx_MyExt_Service_AccessControlService $accessControlService) {
        $this->accessControlService = $accessControlService;
    }
    
    /**
     *
     * @return void
     */
    public function initializeAction() {
          if(TRUE === $this->accessControllService->hasLoggedInFrontendUser()) {
              // Get all the request arguments                    
              $requestArguments = $this->request->getArguments();
              $requestArguments['frontendUser'] = $this->accessControllService->getFrontendUserUid();
              $this->request->setArguments($requestArguments);
          } else {
             // throw an Exception, do redirect, whatever
          }
    }
    
    /**
     *
     * @param Tx_MyExt_Domain_Model_FrontendUser $frontendUser
     */
    public function showExampleUserAction(Tx_MyExt_Domain_Model_FrontendUser $frontendUser) {
           if($this->accessControllService->isAccessAllowed($frontendUser)) {
               $this->view->assign('frontendUser', $frontendUser);            
           } else {
               // do something
           }
    }

    /**
     *
     * @param Tx_MyExt_Domain_Model_FrontendUser $frontendUser
     */
    public function showAllFriendsAction(Tx_MyExt_Domain_Model_FrontendUser $frontendUser) {
           if($this->accessControllService->isAccessAllowed($frontendUser)) {
               $this->view->assign('frontendUser', $frontendUser);            
           } else {
               // do something
           }
    }
}

Auf die Weise kann man jetzt in jeder Action des Controllers auf den gemappten eingeloggten frontendUser zugreifen:

Disclaimer:
Ich habe diesen Blog-Eintrag mehr oder weniger blind geschrieben. Sollte es bei der Umsetzung Problem geben, würde ich mich über eine Rückmeldung freuen. Dann nehme ich Korrekturen gerne vor.

Veröffentlicht von

avatar

Sebastian Schreiber

Ich bin 1980 in Bergisch Gladbach geboren. Nach dem Abitur und Zivildienst habe ich 2000 an der Fachhochschule Lippe & Höxter das Studium der Medienproduktin begonnen und nach längeren Aufenthalten in Valencia und Berlin 2003 das Studium mit dem Abschluss Bachelor of Science in Medienproduktion abgeschlossen. Nach einer Festanstellung kurz nach dem Studium in einer kleinen Webagentur in Köln mit Schwerpunkt TYPO3 bin ich nun seit 2008 freiberuflicher Webentwickler.