Symfony:如果字段为空,则不保存实体,不阻止验证

时间:2016-11-30 14:15:01

标签: symfony doctrine-orm image-upload

我需要实体ProjectImage。它们由OneToOne关系链接。

以下是项目中的属性定义:

  /**
   * @Exclude
   * @ORM\OneToOne(targetEntity="SensoBundle\Entity\Image", cascade={"persist", "remove"})
   * @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
   */
  private $image;

这是图像实体

<?php

namespace SensoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Image
 *
 * @ORM\Table(name="image")
 * @ORM\HasLifecycleCallbacks()
 * @ORM\Entity(repositoryClass="SensoBundle\Repository\ImageRepository")
 */
class Image
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="fileName", type="string", length=255)
     */
    private $fileName;


    /**
     * @var string
     *
     * @ORM\Column(name="parentType", type="string", length=255, nullable=true)
     */
    private $parentType;


    private $tempFilename;


    private $file;

    private $fileNamePrefix;
    private $fileExtension;

    private $hashForName;

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set fileName
     *
     * @param string $fileName
     * @return Image
     */
    public function setFileName($fileName)
    {
        $this->fileName = $fileName;

        return $this;
    }

    /**
     * Get fileName
     *
     * @return string
     */
    public function getFileName()
    {
        return $this->fileName;
    }


    public function getFile()
    {
        return $this->file;
    }

    public function setFile($file = null)
    {
        $this->file = $file;

        if (null !== $this->fileName) {
            $this->tempFilename = $this->fileName;
            $this->fileName     = null;
        }
    }


    public function getUploadDir()
    {

        return '/uploads/img';
    }

    public function getUploadRootDir()
    {

        return __DIR__ . '/../../../web' . $this->getUploadDir();
    }


    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {

        if (null === $this->file) {
            return;
        }

        if (null !== $this->fileName) {
            $this->tempFilename = $this->fileName;
        }

        $this->fileExtension = $this->file->guessExtension();

    }

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    {

        if (null === $this->file) {
            return;
        }

        if (null !== $this->tempFilename) {
            $oldFile = $this->getUploadRootDir() . '/' . $this->tempFilename;
            if (file_exists($oldFile)) {
                unlink($oldFile);
            }
        }

        $this->file->move(
            $this->getUploadRootDir(),
            $this->fileName
        );

    }

    /**
     * @ORM\PreRemove()
     */
    public function preRemoveUpload()
    {
        $this->tempFilename = $this->getUploadRootDir() . '/' . $this->fileName;
    }

    /**
     * @ORM\PostRemove()
     */
    public function removeUplaod()
    {
        if (file_exists($this->tempFilename)) {
            unlink($this->tempFilename);
        }
    }

    public function setFileNamePrefix($prefix)
    {
        $this->fileNamePrefix = $prefix;
    }


    public function setHashForname($hash)
    {
        $this->hashForName = $hash;
    }


    /**
     * Set parentType
     *
     * @param string $parentType
     * @return Image
     */
    public function setParentType($parentType)
    {
        $this->parentType = $parentType;

        return $this;
    }

    /**
     * Get parentType
     *
     * @return string
     */
    public function getParentType()
    {
        return $this->parentType;
    }

    public function getFileExtension() {
        return $this->fileExtension;
    }

    public function getFilenamePrefix() {
        return $this->fileNamePrefix;
    }

}

这是控制器的一部分:

  /**
   * @Route("/project/{id}/presentation/edit", name="project_presentation_edit")
   * @Method({"GET", "POST"})
   */
  public function editPresentationAction(Request $request, $id)
  {

    $entity = $this->get('creasenso.project_repo')->find($id);

    if (!$entity) {
      throw $this->createNotFoundException('The project does not exist');
    }

    $this->denyAccessUnlessGranted('editProject', $entity);

    $form = $this->createForm('CreasensoBundle\Form\Project\ProjectPresentationType', $entity);

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
      $em = $this->getDoctrine()->getManager();
      $em->persist($entity);
      $em->flush();

      $this->get('session')->getFlashBag()->add('success', 'project.presentation.feedback');

      $redirectRoute = ($request->request->get('nextSubmit')) ? 'project_details_edit' : 'project_presentation_edit';

      return $this->redirectToRoute($redirectRoute, array('id' => $id));

    }

    return $this->render('CreasensoBundle:project:editPresentation.html.twig', array(
      'form'   => $form->createView(),
      'entity' => $entity
    ));


  }

这是上面控制器中调用的表单

<?php
// src/Infinite/InvoiceBundle/Form/Type/InvoiceType.php

namespace CreasensoBundle\Form\Project;

use Infinite\FormBundle\Form\Type\PolyCollectionType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ProjectPresentationType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {

    $builder
      ->add('image', 'SensoBundle\Form\Image\ImageSimpleEditType', array(
        'label'             => 'Cover',
        'attr'              => array(
          'help_text' => 'project.cover.help'
        ),
        'display_image_format' => 'projectCoverSmall',
        'imagesConstraints' => array(
          'minWidth' => 300
        )
      ))
      ->add('trans_name_fr', 'SensoBundle\Form\Type\FieldTranslationType', array(
        'mapped'             => false,
        'cascade_validation' => true,
        'fieldName'          => 'name',
        'fieldLocale'        => 'fr',
        'fieldOptions'       => array(
          'label'    => 'French name',
          'required' => true
        )
      ))
      ->add('trans_name', 'SensoBundle\Form\Type\FieldTranslationType', array(
        'mapped'             => false,
        'cascade_validation' => true,
        'fieldName'          => 'name',
        'fieldLocale'        => 'en',
        'fieldOptions'       => array(
          'label'    => 'English name',
          'required' => true
        )
      ))
      ;
  }


  public function getBlockPrefix()
  {
    return 'projectContent';
  }

  /**
   * @param OptionsResolver $resolver
   */
  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults(array(
      'data_class' => 'CreasensoBundle\Entity\Project'
    ));
  }

}

这是我的通用图像实体字段

<?php

namespace SensoBundle\Form\Image;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\Image as ImageValidator;
use SensoBundle\Entity\Image;

class ImageSimpleEditType extends AbstractType
{

  private $imageUrl = null;

  /**
   * @param FormBuilderInterface $builder
   * @param array $options
   */
  public function buildForm(FormBuilderInterface $builder, array $options)
  {


    $builder->addEventListener(FormEvents::POST_SET_DATA, function ($event) use ($builder, $options) {
      $form = $event->getForm();

      $imageFieldParams = array(
        'label'                => false,
        'display_image_format' => $options['display_image_format'],
        'required'             => false
      );


      if (!empty($options['imagesConstraints'])) {


        // Image format
        $constraints     = $options['imagesConstraints'];
        $validatorParams = array();

        if (!empty($constraints['format'])) {

          switch ($constraints['format']) {
            case 'square':
              $squareErrMsg                             = "image.edit.squareError";
              $validatorParams['allowSquare']           = true;
              $validatorParams['allowLandscape']        = false;
              $validatorParams['allowPortrait']         = false;
              $validatorParams['allowLandscapeMessage'] = $squareErrMsg;
              $validatorParams['allowPortraitMessage']  = $squareErrMsg;
              break;
            case 'landscape':
              $landscapeErrMsg                          = "image.edit.landscapeError";
              $validatorParams['allowSquare']           = false;
              $validatorParams['allowLandscape']        = true;
              $validatorParams['allowPortrait']         = false;
              $validatorParams['allowLandscapeMessage'] = $landscapeErrMsg;
              $validatorParams['allowPortraitMessage']  = $landscapeErrMsg;
              break;
            case 'portrait':
              $portraitErrMsg                           = "image.edit.portraitError";
              $validatorParams['allowSquare']           = false;
              $validatorParams['allowLandscape']        = false;
              $validatorParams['allowPortrait']         = true;
              $validatorParams['allowLandscapeMessage'] = $portraitErrMsg;
              $validatorParams['allowPortraitMessage']  = $portraitErrMsg;
              break;
          }

          // Min width
          if (!empty($constraints['minWidth'])) {
            $validatorParams['minWidth'] = $constraints['minWidth'];
          }

        }


        $imageFieldParams['constraints'] = new ImageValidator($validatorParams);


      }


      $form->add('file', 'SensoBundle\Form\Image\ImageInputType', $imageFieldParams);

    });

  }


  /**
   * @param OptionsResolver $resolver
   */
  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults(array(
      'data_class'           => 'SensoBundle\Entity\Image',
      'display_image_format' => 'original',
      'imagesConstraints'    => null
    ));
  }

  public function getBlockPrefix()
  {
    return 'sensoImage';
  }


}

最后,这是我的通用图像文件输入(用于图像实体形式)

<?php

namespace SensoBundle\Form\Image;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormEvents;

use Symfony\Component\Form\Extension\Core\Type\FileType;

use SensoBundle\Entity\Image;


use Symfony\Component\Validator\Constraints\Image as ImageValidator;

class ImageInputType extends AbstractType
{

  private $imageManager;

public function __construct($imageManager)
{
  $this->imageManager = $imageManager;
}


  /**
   * @param FormBuilderInterface $builder
   * @param array $options
   */
  public function buildForm(FormBuilderInterface $builder, array $options)
  {


  }

//
  public function buildView(FormView $view, FormInterface $form, array $options)
  {

    $view->vars['image_url'] = null;
    $imageEntity             = $form->getParent()->getData();
    if ($imageEntity) {
      $this->imageManager->setEntity($imageEntity);
      $view->vars['image_url'] = $this->imageManager->getRelativeUrl();
    }

    $view->vars['display_image_format'] = $options['display_image_format'];
  }

  /**
   * @param OptionsResolver $resolver
   */
  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults(array(
      'display_image_format' => 'original',
      'format'               => null
    ));
  }

  public function getBlockPrefix()
  {
    return 'sensoImageInput';
  }

  public function getParent()
  {
    return 'Symfony\Component\Form\Extension\Core\Type\FileType';
  }


}

我的表单结构就像那样

  • - 项目表单(类ProjectPresentationType)
  • ---- 图片实体字段(类ImageSimpleEditType)
  • ------ 图像输入(类ImageInputType)

我的问题是即使没有上传文件也会创建图像实体。

我希望能够使用这个“功能”创建一个新项目:

  • 不需要图片上传
  • 如果图片字段为空,请勿创建图片实体

感谢您的帮助。

0 个答案:

没有答案