2017-05-05 14 views
1

你好的Silex(與Symfony的)專家介紹,硅石symfony的學說ORM多對多:在登錄getRoles返回空列表

我需要實現通過主義/ ORM數據庫認證用戶/角色模型。

這是我的硅石作曲家設置:

"require": { 
    "silex/web-profiler": "^2.0", 
    "monolog/monolog": "1.13.*", 
    "symfony/twig-bridge": "^3.2", 
    "symfony/monolog-bridge": "^3.2", 
    "symfony/console": "^3.2", 
    "symfony/yaml": "^3.2", 
    "symfony/security-bundle": "^3.2", 
    "doctrine/orm": "^2.5", 
    "dflydev/doctrine-orm-service-provider": "^2.0", 
    "symfony/form": "^3.2", 
    "symfony/validator": "^3.2", 
    "symfony/config": "^3.2", 
    "symfony/doctrine-bridge": "^3.2", 
    "doctrine/migrations": "^1.5" 
}, 

用戶可以註冊。註冊用戶可以登錄和註銷。未註冊的訪問者具有匿名角色。

symfony分析器正在工作,所以我可以看到安全狀態(認證/授權)。我也跟蹤PHP日誌文件的錯誤。

我從這裏開始https://github.com/fredjuvaux/silex-orm-user-provider(用戶從數據庫,角色數組),並試圖擴展它以通過教條多對多關係從數據庫獲取用戶角色。

有:

class MyUserController (different user actions like user,edit, register,...) 
class MyUserManager implements UserProviderInterface (loadUserByUsername, ...) 
class MyUserServiceProvider implements ServiceProviderInterface, ControllerProviderInterface, BootableProviderInterface (controller routing and template setting) 

的ORM實體是:

User: 
/** 
* MyUser 
* 
* @Entity 
* @Table(name="myuser") 
*/ 
class MyUser implements UserInterface, \Serializable 
{ 
.... 

    /** 
    * @ManyToMany(targetEntity="MyRole", inversedBy="users") 
    * 
    */ 
    private $roles; 

... 
    * Constructor. 
    * 
    * @param string $email 
    */ 
    public function __construct($email) 
    { 
     $this->email = $email; 
     $this->created = time(); 
     $this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36); 
     $this->roles = new ArrayCollection(); 

    } 

    ... 

     /** 
    * 
    * @return ArrayCollection list of the user's roles. 
    */ 
    public function getRoles() 
    { 
     $result = $this->roles->toArray(); // throws error for login: 
     // $result = $this->roles; // test // thhrows error : null object 
     dump($this->roles); 
     // $result = array("ROLE_USER", "ROLE_OTHER"); // static setting and 
works for login 
     return $result; 
    } 
    ... 
} 


Roles (implements Roleinterface) 
/** 
* MyRole 
* 
* @Entity 
* @Table(name="myrole") 
*/ 
class MyRole implements RoleInterface 
{ 

    /** 
    * @var string 
    * @Column(name="role", type="string", length=20, unique=true) 
    */ 
    private $role; 

    /** 
    * @ManyToMany(targetEntity="MyUser", mappedBy="roles") 
    */ 
    private $users; 

    ... 
    /* 
    * methods for RoleInterface 
    * @return string|null A string representation of the role, or null 
    */ 
    public function getRole() 
    { 
     $result = $this->role; 
     return $result; 
    } 

} 

當用戶註冊,他得到該會話的ROLE_USER作用, 認證和授權是確定並且用戶在 數據庫中創建。

然後,我可以在新用戶的控制器中爲新用戶分配新角色(「role_test1」,「role_test2」),myuser_myrole被填充(myuser_id myrole_id)。 當我更改角色時,實體管理器會正確更新它們。

當我從UserController中訪問用戶實體進行這項工作,我可以訪問所賦予的角色:

// MyUserController.php 
$user = $em->getRepository('MyEntities\MyUser')->find($id); 
$roles= $user->getRoles() 
$role_length = count($roles); 
$role_list = array(); 
for ($i=0; $i <$role_length ; $i++) 
{ 
     array_push($role_list,$roles[$i]->getRole()); // MyRole::getRole() prints out something to screen. 
} 
printf("<br> role-list:"); dump($role_list); 

調用此控制器打印出通過MyRole :: getRole(所賦予的角色),所以ORM訪問在這裏工作。

現在來怪:

我想登錄登錄表單新用戶。

當我使用

// MyUser::getRoles() 
    return $this->roles; 

它拋出:

Argument 4 passed to Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken::__construct() must be of the type array, object given, 

好吧,使得也許意義,因爲$角色是一個學說的ArrayCollection。

當我使用

// MyUser::getRoles() 
    return $this->roles->toArray(); 

我可以使用用戶口令登錄,但我沒有經過認證(黃色狀態)。拋出角色,我收到一個空數組ArrayCollection。

roles: 
ArrayCollection {#388 ▼ 
    -elements: [] 
} 

UsernamePasswordToken具有空的角色數組。

When I use 
// MyUser::getRoles() 
    return array("ROLE_HELLO1", "ROLE_HELLO2"); // static role array with strings 

我可以登錄並正與這些角色身份驗證:

角色

array:2 [▼ 
    0 => "ROLE_HELLO1" 
    1 => "ROLE_HELLO2" 
] 

有關於這個老文檔爲symfony1.2 2 http://symfony.com/doc/2.0/cookbook/security/entity_provider.html(管理數據庫中的角色),但它不在symfony3中工作。

在這裏,他們使用的用戶管理

//class User 
    public function getRoles() 
    { 
     return $this->groups->toArray(); 
    } 

    //class Group extends Role (not RoleInterface, old?) 
    public function getRole() 
    { 
     return $this->role; 
    } 

實際的symfony文檔不介紹如何使用存儲在數據庫中的作用。

總結:

登錄和用戶/角色不能按預期工作:

MyUser::getRoles() 
  • 不經的教義ORM從數據庫中獲得的角色。

  • 必須返回用於登錄的字符串數組。

  • 在另一個控制器中提供正確的角色關聯。

問題:

(1)這是一個Silex的具體問題?

(2)如何正確使用它或在哪裏找到解決方法的良好鏈接/文檔?

(3)LoadUserByUsername()方法會干涉所有這些嗎?

(4)我是否需要類MyUserRepository extends EntityRepository {}來執行查詢並獲取角色列表?

(5)我是否需要使用角色層次結構服務?

(6)「用戶」和「角色」是否有特殊的命名約定(表名或類名)?

我發現很多帖子詢問相同/相似,但他們在這裏沒有幫助。

謝謝你的幫助,我真的被困在那!

德克

+0

有一個關於[從數據庫加載用戶]的最新文章 – mTorres

回答

0

試試這個:

public function getRoles() 
{ 
    return $this->roles->map(function (MyRole $role) { 
     return $role->getRole(); 
    })->toArray(); 
} 

您也應該檢查是否關係正確保存在數據庫中。 如果有ManyToManyMyUserMyRole之間的關係,您必須確保關係保存在兩個實體中。

//class MyUser 
public function addRole(MyRole $role) 
{ 
    $this-roles->add($role); 
    $role->users->add($user); 
} 
+0

非常感謝你,我嘗試了兩個建議。但沒有改變,從getRoles()返回的Array保持空白。我認爲這種關係是正確的,因爲從MyUser控制器(實體類之外)我可以訪問角色。它是實體內部的MyUser :: getRoles(),而登錄操作會導致問題。也許我可以在登錄時從別的地方訪問entitymanager? – dizz

+0

你檢查過數據庫表是否一切正確?您也可以嘗試檢查ManyToOne關係是否有效。 – miikes

+0

我試過多對一的關係 /** * @ManyToOne(targetEntity =「MyRole」) */ private $ roles;如果我在MyUser.php中使用: public function getRoles() {result = array($ this-> roles-> getRole()); 返回$結果; } 我在登錄時獲得了正確的角色,但這只是一個角色。 – dizz

0

我對此有一個突破,但現在它似乎工作。謝謝你的addRole()建議!

我終於有:MyUser.php:

//Myuser.php 
/** 
* MyUser 
* 
* @Entity 
* @Table(name="myuser") 
*/ 

class MyUser implements UserInterface, \Serializable //, ObjectManagerAware 
{ 
    ... 

    /** 
    * @ManyToMany(targetEntity="MyRole", inversedBy="users") 
    */ 
    private $roles; 

    public function __construct($email) 
    { 
    (...) 
    $this->roles = new ArrayCollection(); 


    /** 
    * 
    * @return ArrayCollection list of the user's roles. 
    */ 
    public function getRoles() 
    { 
     $result = $this->roles->toArray(); 
     return $result; 
    } 

    public function assignToRole($role) 
    { 
     $this->roles[] = $role; 
    } 

    public function setRole($myrole) 
    { 
    $this->roles= $myrole; 
    } 

    public function hasRole($role) 
    { 
     return in_array(strtoupper($role), $this->getRoles(), true); 
    } 

     public function addRole(MyRole $role) 
    { 
     $this->roles->add($role); 
     //$role->users->addRole($this); // could not access roles->user->... 
         // because private variable in MyRole but it works 
    } 

     /** 
    * Remove the given role from the user. 
    * 
    * @param string $role 
    */ 
    public function removeRole($role) 
    { 
     dump($role); 
     $this->roles->removeElement($role); 
    } 

    (...) // other setters getters 

    public function serialize() 
    { 
     return serialize(array(
      $this->id, 
      $this->username, 
      $this->password, 
      $this->salt, 
     )); 
    } 

    /** 
    * @see \Serializable::unserialize() 
    */ 
    public function unserialize($serialized) 
    { 
     list (
      $this->id, 
      $this->username, 
      $this->password, 
      $this->salt, 
      ) = unserialize($serialized); 
    } 
} 

和MyRole.php:

// MyRole.php 

/** 
* MyRole 
* 
* @Entity 
* @Table(name="myrole") 
*/ 
class MyRole implements RoleInterface 
{ 
    (...) 

    /** 
    * @ManyToMany(targetEntity="MyUser", mappedBy="roles") 
    */ 
    private $users; 


    /** 
    * @var string 
    * @Column(name="role", type="string", length=20, unique=true) 
    */ 
    private $role; 


    /* 
    * methods for RoleInterface 
    * @return string|null A string representation of the role, or null 
    */ 
    public function getRole() 
    { 
     $result = $this->role; 
     return ($result); 
    } 

    public function setRole($role) 
    { 
     $this->role= $role; 
     return $this; 
    } 

    (...) 

    /** 
    * Constructor 
    */ 
    public function __construct() 
    { 
     $this->users = new ArrayCollection(); 
    } 

    /** 
    * Add user 
    * @param \MyEntities\MyUser $user 
    * @return MyRole 
    */ 
    public function addUser($user) 
    { 
     $this->users[] = $user; 
     return $this; 
    } 


    public function setUser($user) 
    { 
     $this->users[] = $user; 
     return $this; 
    } 

    /** 
    * Remove user 
    * 
    * @param \MyEntities\MyUser $user 
    */ 
    public function removeUser($user) 
    { 
     $this->users->removeElement($user); 
    } 

    /** 
    * Get users 
    * 
    * @return ArrayCollection $users 
    */ 
    public function getUsers() 
    { 
     return $this->users; 
    } 

    /** 
    * __toString() 
    * 
    * @return string 
    */ 
    public function __toString() 
    { 
     return $this->bezeichnung; 
    } 
} 

隨着學說ORM的命令幫助

vendor/bin/doctrine orm:validate-schema 
vendor/bin/doctrine orm:schema-tool:update --dump-sql 

正確的多對多表myuser_myrole已生成,角色設置在l用戶的ogin。我認爲,最重要的是正確使用函數addRole()(使用this-> roles-> add($ role),而不是像this-> roles-> addRole($ role))。讓教條在背景中做魔術。

感謝您的任何幫助和意見! dirk