ユーザーがプロフィール写真をアップロードして保存できるユーザー プロフィールがあります。
UserProfile エンティティと Document エンティティがあります。
エンティティ/UserProfile.php
namespace Acme\AppBundle\Entity\Profile;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="ISUserProfile")
*/
class UserProfile extends GenericProfile
{
/**
* @ORM\OneToOne(cascade={"persist", "remove"}, targetEntity="Acme\AppBundle\Entity\Document")
* @ORM\JoinColumn(name="picture_id", referencedColumnName="id", onDelete="set null")
*/
protected $picture;
/**
* Set picture
*
* @param Acme\AppBundle\Entity\Document $picture
*/
public function setPicture($picture)
{
$this->picture = $picture;
}
/**
* Get picture
*
* @return Acme\AppBundle\Entity\Document
*/
public function getPicture()
{
return $this->picture;
}
}
エンティティ/Document.php
namespace Acme\AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks
*/
class Document
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $path;
/**
* @Assert\File(maxSize="6000000")
*/
private $file;
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
return 'uploads/documents';
}
/**
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
$this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension();
}
}
/**
* @ORM\PostPersist()
* @ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
/**
* @ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set path
*
* @param string $path
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Get path
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set file
*
* @param string $file
*/
public function setFile($file)
{
$this->file = $file;
}
/**
* Get file
*
* @return string
*/
public function getFile()
{
return $this->file;
}
}
私のユーザー プロファイル フォーム タイプは、ドキュメント フォーム タイプを追加して、ユーザー プロファイル ページにファイル アップローダを含めます。
フォーム/UserProfileType.php
namespace Acme\AppBundle\Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UserProfileType extends GeneralContactType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
/*
if(!($pic=$builder->getData()->getPicture()) || $pic->getWebPath()==''){
$builder->add('picture', new DocumentType());
}
*/
$builder
->add('picture', new DocumentType());
//and add some other stuff like name, phone number, etc
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\AppBundle\Entity\Profile\UserProfile',
'intention' => 'user_picture',
'cascade_validation' => true,
));
}
public function getName()
{
return 'user_profile_form';
}
}
フォーム/DocumentType.php
namespace Acme\AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class DocumentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\AppBundle\Entity\Document',
));
}
public function getName()
{
return 'document_form';
}
}
私のコントローラーには、プロファイルの更新アクションがあります。
コントローラー/ProfileController.php
namespace Acme\AppBundle\Controller;
class AccountManagementController extends BaseController
{
/**
* @param Symfony\Component\HttpFoundation\Request
* @return Symfony\Component\HttpFoundation\Response
*/
public function userProfileAction(Request $request) {
$user = $this->getCurrentUser();
$entityManager = $this->getDoctrine()->getEntityManager();
if($user && !($userProfile = $user->getUserProfile())){
$userProfile = new UserProfile();
$userProfile->setUser($user);
}
$uploadedFile = $request->files->get('user_profile_form');
if ($uploadedFile['picture']['file'] != NULL) {
$userProfile->setPicture(NULL);
}
$userProfileForm = $this->createForm(new UserProfileType(), $userProfile);
if ($request->getMethod() == 'POST') {
$userProfileForm->bindRequest($request);
if ($userProfileForm->isValid()) {
$entityManager->persist($userProfile);
$entityManager->flush();
$this->get('session')->setFlash('notice', 'Your user profile was successfully updated.');
return $this->redirect($this->get('router')->generate($request->get('_route')));
} else {
$this->get('session')->setFlash('error', 'There was an error while updating your user profile.');
}
}
$bindings = array(
'user_profile_form' => $userProfileForm->createView(),
);
return $this->render('user-profile-template.html.twig', $bindings);
}
}
さて、このコードは機能します...しかし、それは地獄のように醜いです. アップロードされたファイルのリクエスト オブジェクトをチェックし、ピクチャを null に設定して、新しい Document エンティティを保持する必要があることを Symfony が認識しなければならないのはなぜですか?
プロフィール画像として画像をアップロードするオプションを備えたシンプルなユーザー プロフィール ページを用意することは、これよりも簡単であるはずです。
私は何が欠けていますか??