我即将尝试在我正在使用的FOSUserBundle
的symfony2项目中尝试将个人资料图片字段添加到我的用户实体。我觉得这应该很简单,但是,我没有找到任何有用的文档来解释如何做到这一点。
目前,我正计划在我的表单对象(我已从通用ProfileEdit
表单扩展)中添加一个未映射的字段,该字段采用上传的文件。然后,我将为FOSUserEvents::PROFILE_EDIT_SUCCESS
或FOSUserEvents::PROFILE_EDIT_COMPLETED
创建一个事件监听器,它将采用表单,处理文件上传并保留上传文件的路径(使用方法获取公共URL和绝对值路径)到我的User对象,然后向Response flashbag添加消息,说它成功或不成功。这真的是正确/最佳实践方式吗?或者我错过了什么?这个功能真的还没有包含在FOSUserBundle中吗?如果是这样的话,我没有找到它的文档,但是如果它是......那就会喜欢它。
非常感谢任何帮助/提示/伏都教建议!
答案 0 :(得分:8)
所以,事实证明我在回答这个问题时迷路了:文件上传本身不需要由FOSUserBundle处理,而是由Doctrine处理。我向我的User实体添加了一个属性,该属性不是持久化的,但是表单只是用它来编辑用户的配置文件。在下面的代码中,此属性为$profilePictureFile
。然后,生命周期回调确保在保留实体之前将此文件复制到相关位置(类似于编辑和删除时)。
尽管如此,我想我会在这里发布一个答案,以帮助那些发现自己希望将来在FOSUserBundle中向用户添加个人资料图片的人。
相关文件是: http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/overriding_forms.rst
<?php
// DAWeldonExampleBundle/Entity/User.php
namespace DAWeldon\Example\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Security\Core\Util\SecureRandom;
/**
* @ORM\Entity()
* @ORM\HasLifecycleCallbacks()
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="datetime")
*/
protected $lastEdited;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank(message="Please enter your surname.", groups={"Registration", "Profile"})
*/
protected $surname;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank(message="Please enter your forename.", groups={"Registration", "Profile"})
*/
protected $forename;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $nickname;
/**
* @Assert\File(maxSize="2048k")
* @Assert\Image(mimeTypesMessage="Please upload a valid image.")
*/
protected $profilePictureFile;
// for temporary storage
private $tempProfilePicturePath;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $profilePicturePath;
public function __construct()
{
parent::__construct();
// your own logic
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set surname
*
* @param string $surname
* @return User
*/
public function setSurname($surname)
{
$this->surname = $surname;
return $this;
}
/**
* Get surname
*
* @return string
*/
public function getSurname()
{
return $this->surname;
}
/**
* Set forename
*
* @param string $forename
* @return User
*/
public function setForename($forename)
{
$this->forename = $forename;
return $this;
}
/**
* Get forename
*
* @return string
*/
public function getForename()
{
return $this->forename;
}
/**
* Asks whether the user is granted a particular role
*
* @return boolean
*/
public function isGranted($role)
{
return in_array($role, $this->getRoles());
}
/**
* Set nickname
*
* @param string $nickname
* @return User
*/
public function setNickname($nickname)
{
$this->nickname = $nickname;
return $this;
}
/**
* Get nickname
*
* @return string
*/
public function getNickname()
{
return $this->nickname;
}
/**
* Get the best way to address this person
*
* @return string
*/
public function getBestAddress() {
if (empty($this->getNickname()) and empty($this->getForename()) && empty($this->getSurname())) {
return $this->getUsername();
}
elseif (empty($this->getNickname())) {
return $this->getForename().' '.$this->getSurname();
}
else {
return $this->getNickname();
}
}
/**
* Sets the file used for profile picture uploads
*
* @param UploadedFile $file
* @return object
*/
public function setProfilePictureFile(UploadedFile $file = null) {
// set the value of the holder
$this->profilePictureFile = $file;
// check if we have an old image path
if (isset($this->profilePicturePath)) {
// store the old name to delete after the update
$this->tempProfilePicturePath = $this->profilePicturePath;
$this->profilePicturePath = null;
} else {
$this->profilePicturePath = 'initial';
}
return $this;
}
/**
* Get the file used for profile picture uploads
*
* @return UploadedFile
*/
public function getProfilePictureFile() {
return $this->profilePictureFile;
}
/**
* Set profilePicturePath
*
* @param string $profilePicturePath
* @return User
*/
public function setProfilePicturePath($profilePicturePath)
{
$this->profilePicturePath = $profilePicturePath;
return $this;
}
/**
* Get profilePicturePath
*
* @return string
*/
public function getProfilePicturePath()
{
return $this->profilePicturePath;
}
/**
* Get the absolute path of the profilePicturePath
*/
public function getProfilePictureAbsolutePath() {
return null === $this->profilePicturePath
? null
: $this->getUploadRootDir().'/'.$this->profilePicturePath;
}
/**
* Get root directory for file uploads
*
* @return string
*/
protected function getUploadRootDir($type='profilePicture') {
// the absolute directory path where uploaded
// documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir($type);
}
/**
* Specifies where in the /web directory profile pic uploads are stored
*
* @return string
*/
protected function getUploadDir($type='profilePicture') {
// the type param is to change these methods at a later date for more file uploads
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/user/profilepics';
}
/**
* Get the web path for the user
*
* @return string
*/
public function getWebProfilePicturePath() {
return '/'.$this->getUploadDir().'/'.$this->getProfilePicturePath();
}
/**
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function preUploadProfilePicture() {
if (null !== $this->getProfilePictureFile()) {
// a file was uploaded
// generate a unique filename
$filename = $this->generateRandomProfilePictureFilename();
$this->setProfilePicturePath($filename.'.'.$this->getProfilePictureFile()->guessExtension());
}
}
/**
* Generates a 32 char long random filename
*
* @return string
*/
public function generateRandomProfilePictureFilename() {
$count = 0;
do {
$generator = new SecureRandom();
$random = $generator->nextBytes(16);
$randomString = bin2hex($random);
$count++;
}
while(file_exists($this->getUploadRootDir().'/'.$randomString.'.'.$this->getProfilePictureFile()->guessExtension()) && $count < 50);
return $randomString;
}
/**
* @ORM\PostPersist()
* @ORM\PostUpdate()
*
* Upload the profile picture
*
* @return mixed
*/
public function uploadProfilePicture() {
// check there is a profile pic to upload
if ($this->getProfilePictureFile() === null) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->getProfilePictureFile()->move($this->getUploadRootDir(), $this->getProfilePicturePath());
// check if we have an old image
if (isset($this->tempProfilePicturePath) && file_exists($this->getUploadRootDir().'/'.$this->tempProfilePicturePath)) {
// delete the old image
unlink($this->getUploadRootDir().'/'.$this->tempProfilePicturePath);
// clear the temp image path
$this->tempProfilePicturePath = null;
}
$this->profilePictureFile = null;
}
/**
* @ORM\PostRemove()
*/
public function removeProfilePictureFile()
{
if ($file = $this->getProfilePictureAbsolutePath() && file_exists($this->getProfilePictureAbsolutePath())) {
unlink($file);
}
}
/**
* Set lastEdited
*
* @param \DateTime $lastEdited
* @return User
*/
public function setLastEdited($lastEdited)
{
$this->lastEdited = $lastEdited;
return $this;
}
/**
* Get lastEdited
*
* @return \DateTime
*/
public function getLastEdited()
{
return $this->lastEdited;
}
/**
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function setLastEditedValueAsNow() {
$this->setLastEdited(new \DateTime());
}
}
当然,个人资料表格如下:
<?php
// DAWeldonExampleBundle/Form/Type/ProfileFormType.php
namespace DAWeldon\Example\UserBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ProfileFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// add your custom field
$builder->add('username')
->add('surname')
->add('forename')
->add('nickname')
->add('profilePictureFile');
}
public function getParent()
{
return 'fos_user_profile';
}
public function getName()
{
return 'readypeeps_user_profile';
}
}