这里有一个问题,我不得不打扰一下,我希望我们先考虑一点点序列化问题。当我们用户登录后,会得到一个User实体,这个User实体会存储在session中。为此,为了节省资源,应该让php序列化User对象并储存在session中,当用户请求页面,再将该序列化字符串反解成User对象。
如果你感觉真的很好奇,序列化和反序列化用户信息的类被称为ContextListener。
这是伟大的!但是,doctrine会出现一些疑难杂症。有时,doctrine会把一些额外没有用的信息放到我们的实体中,例如entity manager:这个东西保存了一些很大又重要的信息。
虽然很重要,但是通常,我们用不到这些。如果我们把所有的内容都序列化到session中很可能导致失败。而且这个entity manager包含数据库连接和其他信息,他们很私密所以不能被序列化。
使用Serializable接口
我们需要帮助doctrine,开始添加Serializable接口到User类。这个接口需要实现两个方法:serialize和 unserialize:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// src/Yoda/UserBundle/Entity/User.php // ... use Serializable; class User implements AdvancedUserInterface, Serializable { // ... public function serialize() { // todo - do some mad serialization } public function unserialize($serialized) { // todo - and some equally angry de-serialization } } |
当user对象去序列化,他就会调用serialize方法,去替代自动方法。当字符串反序列化,unserialize方法就会被调用。看上去很奇怪,但是只有这样才能帮助我们返回一个序列化的数组,里面包含id、username、password,对于unserialize,也仅仅是这三个值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// src/Yoda/UserBundle/Entity/User.php // .. public function serialize() { return serialize(array( $this->id, $this->username, $this->password, )); } public function unserialize($serialized) { list ( $this->id, $this->username, $this->password, ) = unserialize($serialized); } |
你仔细想想,我们好像破坏了一些事情。当symfony从session中获取一些数据并反序列化它,我们最终得到的是一个丢失的数据,例如:roles和isActive。这就不酷了!很糟糕
多虑了:symfony安全系统非常的聪明,在每次请求时会利用id查询出一个新的完整的User对象副本。
我们可以在debug工具条中看到:一旦用户登录,这个请求就会从数据库中抓取当前用户。所以说,没有问题!