2010-09-12 32 views
1

我正在考慮實現條件許可的最佳方式,即用戶和團隊是m-to-m。但是每個團隊也與用戶表有一對一的「領導者」關係。Symfony/sfDoctrineGuard有條件許可

爲了簡單起見,假設我們有兩個權限級別「用戶」和「管理員」。然後可以說,只有某些團隊管理任務,即羣組電子郵件,只能由該團隊的領導發送。

目前,每個針對團隊領導者的操作都會查詢數據庫,以檢查當前用戶是團隊領導者(記住用戶可能會領導多個團隊)。我個人不喜歡看到「if($ user-> isLeader($ team))」到處都是。

我已經考慮設置用戶在登錄用戶會話(ala phpBB)時使用的團隊列表,或者使用symfony過濾器來執行相同的操作。

但是,在第一種方法中,如果其他用戶可能會更改團隊的領導者,則數據可能會過時。第二種方法需要對每個頁面加載額外的數據庫查詢。

有什麼更好的點子? 注意:在一個項目中有多個應用程序需要共享相同的權限模型(即後端和api)

回答

0

我看到2個選項:

覆蓋sfDoctrineGuardUser::getGuardUser()

覆蓋的sfDoctrineGuardUser的getGuardUser方法時,得到它取小組的用戶。這需要額外的左連接,但它可以節省您以後的查詢。

/** 
* Overridden getGuardUser to automatically fetch Teams with User 
* @see plugins/sfDoctrineGuardPlugin/lib/user/sfGuardSecurityUser#getGuardUser() 
*/ 
public function getGuardUser() 
{ 
    if (!$this->user && $id = $this->getAttribute('user_id', null, 'sfGuardSecurityUser')) 
    { 
    $this->user = sfGuardUserTable::findUserByIdWithTeams($id); //write this query to fetch a user with his teams 

    if (!$this->user) 
    { 
     // the user does not exist anymore in the database 
     $this->signOut(); 

     throw new sfException('The user does not exist anymore in the database.'); 
    } 
    } 

    return $this->user; 
} 

然後,您可以根據通過過濾器或通過重寫hasCredential他的團隊添加用戶的憑據。

的Invalidate緩存球隊狀態

如果你不希望任何其他查詢,唯一的附加選項我看到的是使用全局高速緩存。這將涉及以下內容:

  • 緩存用戶對登錄
  • 隊伍或團隊基於證書當組長被刪除或添加,這樣做apc_add(team_invalid_[team_id], true, [length_of_session])
  • 每當添加用戶的憑據(經第一個選項中描述的方法之一),請檢查緩存以查看它們是否無效。
+0

這非常接近我所追求的。 我可能會使用memcache實現類似的解決方案。 – xzyfer 2010-09-14 11:29:57

0

我已經通過在myUser中覆蓋hasCredential方法來實現類似的目的,憑證是必需的。

如:

public function hasCredential($credential, $useAnd = true) { 

    // make sure the symfony core always passes the team leader permission, we handle it later ourselves 
    $this->addCredential('team_leader'); 
    $ret = parent::hasCredential($credential, $useAnd); 

    // if other checks have failed, return false now, no point continuing 
    if (!$ret) return false; 

    if ($credential == 'team_leader' || (is_array($credential) && in_array('team_leader', $credential))) { 
    // do stuff here. in this example, we get the object from a route and check the user is a leader 
    $route = sfcontext::getinstance()->getRequest()->getAttribute('sf_route'); 
    if (!$route instanceof sfObjectRoute) { 
     throw new sfConfigurationException(sprintf('team_leader credential cannot be used against routes of class %s - must be sfObjectRoute', get_class($route))); 
    } 
    return $this->isLeader($route->getObject()); 
    } 
    return $ret; 
} 

然後,您可以添加 「team_leader」 憑證security.yml像使用任何其他。

顯然這取決於你使用sfObjectRoutes,所以如果你不能做到這一點並且不能適應你正在使用的東西,但是我認爲它是一個很好的解決方案,當你可以使用它時!

如果你擔心額外的查詢,你可以看看圍繞isLeader調用的一些緩存。