【问题标题】:Symfony 2.5.6 - UnexpectedTypeException being thrown in a custom form typeSymfony 2.5.6 - 在自定义表单类型中抛出 UnexpectedTypeException
【发布时间】:2014-11-08 17:47:11
【问题描述】:

我有以下表单类型:

class GalleryImageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('thumb', new GalleryThumbnailImage(), array('label' => 'Thumbnail Image'))
            ->add('full', new GalleryFullSizeImage(), array('label' => 'Full Size Image'));
    }

    public function getName()
    {
        return 'galleryImage';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'MajorProductions\SewingDiva\SiteBundle\Entity\GalleryImage'));
    }
}

以及以下实体:

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="GalleryImage", indexes={@ORM\Index(name="id_idx", columns={"id"})})
 */
class GalleryImage
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToOne(targetEntity="GalleryThumbnailImage", mappedBy="galleryImage")
     */
    private $thumb;

    /**
     * @ORM\OneToOne(targetEntity="GalleryFullSizeImage", mappedBy="galleryImage")
     */
    private $full;

    /**
     * @ORM\Column(name="lastModified", type="datetime", nullable=true)
     */
    private $lastModified;

    public function getId()
    {
        return $this->id;
    }

    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return GalleryFullSizeImage
     */
    public function getFull()
    {
        return $this->full;
    }

    /**
     * @param GalleryFullSizeImage $full
     */
    public function setFull(Full $full)
    {
        $this->full = $full;
    }

    /**
     * @return GalleryThumbnailImage
     */
    public function getThumb()
    {
        return $this->thumb;
    }

    /**
     * @param GalleryThumbnailImage $thumb
     */
    public function setThumb(Thumb $thumb)
    {
        $this->thumb = $thumb;
    }

    /**
     * @return \DateTime
     */
    public function getLastModified()
    {
        return $this->lastModified;
    }

    /**
     * @param \DateTime $lastModified
     */
    public function setLastModified(\DateTime $lastModified)
    {
        $this->lastModified = $lastModified;
    }
}

// ----

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="GalleryFullSizeImage", indexes={@ORM\Index(name="id_idx", columns={"id"})})
 */
class GalleryFullSizeImage
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToOne(targetEntity="GalleryImage", inversedBy="full")
     * @ORM\JoinColumn(name="galleryImageId", referencedColumnName="id", onDelete="SET NULL")
     */
    private $galleryImage;

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

    /**
     * @Assert\Image(maxSize="6000000")
     */
    private $file;

    private $tmp;

    public function getId()
    {
        return $this->id;
    }

    public function setId($id)
    {
        $this->id = $id;
    }

    public function getGalleryImage()
    {
        return $this->galleryImage;
    }

    public function setGalleryImage(GalleryImage $galleryImage)
    {
        $this->galleryImage = $galleryImage;
    }

    public function getWebPath()
    {
        return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path;
    }

    protected function getUploadRootDir()
    {
        // the absolute directory path where uploaded
        // documents should be saved
        return __DIR__ . '/../../../../web/' . $this->getUploadDir() . '/full';
    }

    protected function getUploadDir()
    {
        // get rid of the __DIR__ so it doesn't screw up
        // when displaying uploaded doc/image in the view.
        return 'uploads/gallery';
    }

    /**
     * Sets file.
     *
     * @param UploadedFile $file
     */
    public function setFile(UploadedFile $file = null)
    {
        $this->file = $file;
        // check if we have an old image path
        if (is_file($this->getAbsolutePath())) {
            // store the old name to delete after the update
            $this->tmp = $this->getAbsolutePath();
        } else {
            $this->path = 'initial';
        }
    }

    /**
     * Returns file
     *
     * @return mixed
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {
        if (null !== $this->getFile()) {
            $this->path = $this->getFile()->guessExtension();
        }
    }

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    {
        if (null === $this->getFile()) {
            return;
        }

        // check if we have an old image
        if (isset($this->tmp)) {
            // delete the old image
            unlink($this->tmp);
            // clear the temp image path
            $this->tmp = null;
        }

        $this->getFile()->move(
            $this->getUploadRootDir(),
            $this->id . '.' . $this->getFile()->guessExtension()
        );

        $this->setFile(null);
        $this->galleryImage->setLastModified(new \DateTime(null));
    }

    /**
     * @ORM\PreRemove()
     */
    public function storeFilenameForRemove()
    {
        $this->tmp = $this->getAbsolutePath();
    }

    /**
     * @ORM\PostRemove()
     */
    public function removeUpload()
    {
        if (isset($this->tmp)) {
            unlink($this->tmp);
            $this->galleryImage->setLastModified(new \DateTime(null));
        }
    }

    public function getAbsolutePath()
    {
        return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->id . '.' . $this->path;
    }
}

// ----

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="GalleryThumbnailImage", indexes={@ORM\Index(name="id_idx", columns={"id"})})
 */
class GalleryThumbnailImage
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToOne(targetEntity="GalleryImage", inversedBy="thumb")
     * @ORM\JoinColumn(name="galleryImageId", referencedColumnName="id", onDelete="SET NULL")
     */
    private $galleryImage;

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

    /**
     * @Assert\Image(maxSize="6000000")
     */
    private $file;

    private $tmp;

    public function getId()
    {
        return $this->id;
    }

    public function setId($id)
    {
        $this->id = $id;
    }

    public function getGalleryImage()
    {
        return $this->galleryImage;
    }

    public function setGalleryImage(GalleryImage $galleryImage)
    {
        $this->galleryImage = $galleryImage;
    }

    public function getWebPath()
    {
        return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path;
    }

    protected function getUploadRootDir()
    {
        // the absolute directory path where uploaded
        // documents should be saved
        return __DIR__ . '/../../../../web/' . $this->getUploadDir() . '/thumbs';
    }

    protected function getUploadDir()
    {
        // get rid of the __DIR__ so it doesn't screw up
        // when displaying uploaded doc/image in the view.
        return 'uploads/gallery';
    }

    /**
     * Sets file.
     *
     * @param UploadedFile $file
     */
    public function setFile(UploadedFile $file = null)
    {
        $this->file = $file;
        // check if we have an old image path
        if (is_file($this->getAbsolutePath())) {
            // store the old name to delete after the update
            $this->tmp = $this->getAbsolutePath();
        } else {
            $this->path = 'initial';
        }
    }

    /**
     * Returns file
     *
     * @return mixed
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {
        if (null !== $this->getFile()) {
            $this->path = $this->getFile()->guessExtension();
        }
    }

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    {
        if (null === $this->getFile()) {
            return;
        }

        // check if we have an old image
        if (isset($this->tmp)) {
            // delete the old image
            unlink($this->tmp);
            // clear the temp image path
            $this->tmp = null;
        }

        $this->getFile()->move(
            $this->getUploadRootDir(),
            $this->id . '.' . $this->getFile()->guessExtension()
        );

        $this->setFile(null);
        $this->galleryImage->setLastModified(new \DateTime(null));
    }

    /**
     * @ORM\PreRemove()
     */
    public function storeFilenameForRemove()
    {
        $this->tmp = $this->getAbsolutePath();
    }

    /**
     * @ORM\PostRemove()
     */
    public function removeUpload()
    {
        if (isset($this->tmp)) {
            unlink($this->tmp);
            $this->galleryImage->setLastModified(new \DateTime(null));
        }
    }

    public function getAbsolutePath()
    {
        return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->id . '.' . $this->path;
    }
}

当我尝试查看表单本身时,我从UnexpectedTypeException 收到以下错误消息:

给定类型“字符串或 Symfony\Component\Form\FormTypeInterface”、“MajorProductions\SewingDiva\SiteBundle\Entity\GalleryThumbnailImage”的预期参数

所以,我的 GalleryThumbnailImage 字段的 FormBuilder 添加令人窒息,认为它应该由字符串而不是该对象支持。但是,我真的不知道它为什么会这样做。可能是因为我在GalleryImage 中使用了命名空间别名(Thumb 代替了GalleryThumbnailImageFull 代替了GalleryFullSizeImage)?还是我遗漏了一些明显的东西?


编辑:即使在为 GalleryFullSizeImageGalleryThumbnailImage 创建表单类型之后,问题仍然存在:

namespace MajorProductions\SewingDiva\SiteBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class GalleryFullSizeImageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('file', 'file');
    }

    public function getName()
    {
        return 'galleryFullSizeImage';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'MajorProductions\SewingDiva\SiteBundle\Entity\GalleryFullSizeImage'));
    }
}

// ----

namespace MajorProductions\SewingDiva\SiteBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class GalleryThumbnailImageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('file', 'file');
    }

    public function getName()
    {
        return 'galleryThumbnailImage';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'MajorProductions\SewingDiva\SiteBundle\Entity\GalleryThumbnailImage'));
    }
}

请注意,// ---- 写在我的代码中,它代表一个文件的结尾和另一个文件的开头。考虑到带有所有 Doctrine 注释的实体代码的长度,我想通过将各个类的代码放在相同的代码块中来节省一些垂直空间。

【问题讨论】:

  • 您不能只将任何类作为表单类型。 Symfony2 应该如何知道如何处理/提交/渲染这个元素?您需要创建一个表单类型来封装有关您的实体的基本原始信息,然后将该数据转换为 PHP 代码中的完整对象。
  • 由于这些是子实体(GalleryImage 本质上是另外两个的容器),我假设您的意思是我还需要为它们中的每一个创建一个表单类型。跨度>
  • 问题仍然存在。见编辑。

标签: php symfony


【解决方案1】:

你使用:

$builder
    ->add('thumb', new GalleryThumbnailImage(), array('label' => 'Thumbnail Image'))
    ->add('full', new GalleryFullSizeImage(), array('label' => 'Full Size Image'));

让我们回忆一下FormBuilder#add() 的参数是什么:public function add($child, $type = null, array $options = array())。您似乎传递了一个实体,而不是 $type。你想在这里通过的课程是GalleryThumbnailImageTypeGalleryFullSizeImageType。这些类确实实现了FormTypeInterface,所以一切正常!

你需要使用的代码:

$builder
    ->add('thumb', new GalleryThumbnailImageType(), array('label' => 'Thumbnail Image'))
    ->add('full', new GalleryFullSizeImageType(), array('label' => 'Full Size Image'));

【讨论】:

  • 真正可悲的是,我基于另一个项目,该项目具有类似的父->子设置和文件处理,并且它的表单类型就在那里。昨晚我一直盯着它看,但没有注意到。啊。感谢您的帮助:)
猜你喜欢
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多