Symfony2 - 嵌入式表单不显示

时间:2013-08-22 12:56:14

标签: php forms symfony doctrine-orm symfony-2.3

我有两个实体,Kitchen和KitchenImage。 Kitchens的子图像存储在KitchenImage实体中。

我遇到的问题是没有显示Kitc​​henImage的文件输入框,但是它的标签是?

Twig文件:

<div class="row">
    <div class="col-md-12">
        {{ form_start(form, {'attr': {'role': 'form'}}) }}
            <div class="form-group">
                {{ form_label(form.name, 'Title') }}
                {{ form_errors(form.name) }}
                {{ form_widget(form.name, {'attr': {'class': 'form-control', 'placeholder': 'Enter title' }}) }}
            </div>
            <div class="row">
                <div class="form-group col-md-3">
                    {{ form_label(form.image, 'Main Image') }}
                    {{ form_errors(form.image) }}
                    {{ form_widget(form.image) }}
                    <p class="help-block">Main Image</p>
                </div>
                <div class="form-group col-md-3">
                    {{ form_label(form.images, 'Sub Images') }}
                    {{ form_errors(form.images) }}
                    {{ form_widget(form.images) }}
                    <p class="help-block">Sub Images</p>
                </div>
            </div>
            <div class="form-group">
                {{ form_label(form.description) }}
                {{ form_errors(form.description) }}
                {{ form_widget(form.description, {'attr': {'class': 'form-control' }}) }}
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
        {{ form_end(form) }}
    </div>
</div>

控制器

<?php

namespace PWD\AdminBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

use PWD\AdminBundle\Form\Type\KitchenType;
use PWD\AdminBundle\Form\Type\KitchenImageType;
use PWD\WebsiteBundle\Entity\Kitchen;
use PWD\WebsiteBundle\Entity\KitchenImage;

class KitchenController extends Controller
{

    public function addAction(Request $request)
    {
        $kitchen = new Kitchen();
        $form = $this->createForm(new KitchenType(), $kitchen);
        $form->handleRequest($request);

        if ($form->isValid())
        {
            return "Yeah!";
        }

        return $this->render('PWDAdminBundle:Pages:add-kitchen.html.twig', array(
            'form' => $form->createView(),
        ));
    }
}

KitchenType

<?php

namespace PWD\AdminBundle\Form\Type;

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

class KitchenType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
                ->add('name', 'text')
                ->add('description', 'textarea')
                ->add('image', 'file')
                ->add('images', 'collection', array(
                    'type' => new KitchenImageType(),
                    'cascade_validation' => true,
                    ));
    }

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

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'PWD\WebsiteBundle\Entity\Kitchen',
            'cascade_validation' => true,
        ));
    }
}

KitchenImageType

<?php 

namespace PWD\AdminBundle\Form\Type;

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

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

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'PWD\WebsiteBundle\Entity\KitchenImage',
            'cascade_validation' => true,
            'allow_add'    => true,
        ));
    }

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

KitchenImage实体

<?php

namespace PWD\WebsiteBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

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

/**
 * KitchenImage
 *
 * @ORM\Table(name="kitchen_image")
 * @ORM\Entity
 */
class KitchenImage
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @Assert\File(maxSize="6000000")
     * @Assert\Image(
     *     minWidth = 800,
     *     maxWidth = 800,
     *     minHeight = 467,
     *     maxHeight = 467
     * )
     */
    public $image;

    /**
     * @ORM\ManyToOne(targetEntity="Kitchen", inversedBy="image")
     * @ORM\JoinColumn(name="kitchen_id", referencedColumnName="id")
     */
    protected $kitchen;

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

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

    /**
     * Set image
     *
     * @param UploadedFile $file
     */
    public function setImage(UploadedFile $image = null)
    {
        $this->image = $image;
    }

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

    /**
     * Set kitchen
     *
     * @param \PWD\WebsiteBundle\Entity\Kitchen $kitchen
     * @return KitchenImage
     */
    public function setKitchen(\PWD\WebsiteBundle\Entity\Kitchen $kitchen = null)
    {
        $this->kitchen = $kitchen;

        return $this;
    }

    /**
     * Get kitchen
     *
     * @return \PWD\WebsiteBundle\Entity\Kitchen 
     */
    public function getKitchen()
    {
        return $this->kitchen;
    }

    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 up
        // when displaying uploaded doc/image in the view.
        return 'uploads/our-work';
    }

    public function upload()
    {
    // the file property can be empty if the field is not required
    if (null === $this->getImage()) {
        return;
    }

    // use the original file name here but you should
    // sanitize it at least to avoid any security issues

    // move takes the target directory and then the
    // target filename to move to
    $this->getImage()->move(
        $this->getUploadRootDir(),
        $this->getImage()->getClientOriginalName()
    );

    // set the path property to the filename where you've saved the file
    $this->path = $this->getImage()->getClientOriginalName();

    // clean up the file property as you won't need it anymore
    $this->image = null;
    }

    /**
     * Set path
     *
     * @param string $path
     * @return KitchenImage
     */
    public function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

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

厨房实体

<?php 

namespace PWD\WebsiteBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

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

/**
 * @ORM\Entity
 * @ORM\Table(name="kitchen")
 */
class Kitchen
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=100)
     * @Assert\NotBlank()
     */
    protected $name;

    /**
     * @ORM\Column(type="text")
     * @Assert\NotBlank()
     */
    protected $description;

    /**
     * @Assert\File(maxSize="6000000")
     * @Assert\NotNull()
     * @Assert\Image(
     *     minWidth = 800,
     *     maxWidth = 800,
     *     minHeight = 467,
     *     maxHeight = 467
     * )
     */
    protected $image;

    /**
     * @ORM\OneToMany(targetEntity="KitchenImage", mappedBy="kitchen")
     * @Assert\Type(type="PWD\WebsiteBundle\Entity\KitchenImage")
     */
    protected $images;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $imagePath;

    public function __construct()
    {
        $this->images = new ArrayCollection();
    }

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

    /**
     * Set name
     *
     * @param string $name
     * @return Kitchen
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set description
     *
     * @param string $description
     * @return Kitchen
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

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

    /**
     * Set image
     *
     * @param UploadedFile $image
     * @return Kitchen
     */
    public function setImage(UploadedFile $image = null)
    {
        $this->image = $image;
    }

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

    /**
     * Add images
     *
     * @param \PWD\WebsiteBundle\Entity\KitchenImage $images
     * @return Kitchen
     */
    public function addImage(\PWD\WebsiteBundle\Entity\KitchenImage $images)
    {
        $this->images[] = $images;

        return $this;
    }

    /**
     * Remove images
     *
     * @param \PWD\WebsiteBundle\Entity\KitchenImage $images
     */
    public function removeImage(\PWD\WebsiteBundle\Entity\KitchenImage $images)
    {
        $this->images->removeElement($images);
    }

    /**
     * Get images
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getImages()
    {
        return $this->images;
    }

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

    /**
     * Get web path
     */
    public function getWebPath()
    {
        return null === $this->path
            ? null
            : $this->getUploadDir().'/'.$this->imagePath;
    }

    /**
     * Get upload root directory
     */
    protected function getUploadRootDir()
    {
        return __DIR__.'/../../../../web/'.$this->getUploadDir();
    }

    /**
     * Get upload directory
     */
    protected function getUploadDir()
    {
        return 'uploads/our-work';
    }

    /**
     * Upload image
     */
    public function upload()
    {
    // The file property can be empty if the field is not required
    if (null === $this->getImage()) {
        return;
    }

    // move takes the target directory and then the
    // target filename to move to
    $this->getImage()->move(
        $this->getUploadRootDir(),
        $this->getImage()->getClientOriginalName()
    );

    // set the path property to the filename where you've saved the file
    $this->imagePath = $this->getImage()->getClientOriginalName();

    // clean up the file property as you won't need it anymore
    $this->image = null;
    }

    /**
     * Set imagePath
     *
     * @param string $imagePath
     * @return Kitchen
     */
    public function setImagePath($imagePath)
    {
        $this->imagePath = $imagePath;

        return $this;
    }

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

1 个答案:

答案 0 :(得分:0)

我很确定问题是你的KitchenImageType中有allow_add,它应该在你的KitchenType中的集合上

class KitchenType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
    $builder
            ->add('name', 'text')
            ->add('description', 'textarea')
            ->add('image', 'file')
            ->add('images', 'collection', array(
                'type' => new KitchenImageType(),
                'cascade_validation' => true,
                'allow_add' => true, // *** Need this here, remove it from KitchenImageType
                ));
}

可能还有其他问题,但我认为就是这样。您可能希望仔细阅读本书中的示例:http://symfony.com/doc/current/cookbook/form/form_collections.html。要让新东西发挥作用,需要做很多事情。

==================================

要回复关于添加厨房图像以进行测试的评论,只需

public function addAction(Request $request)
{
    $kitchen = new Kitchen();
    $kitchen->addImage(new KitchenImage());
    $form = $this->createForm(new KitchenType(), $kitchen);

图像和图像属性有点令人困惑。稍后您可能希望将图像重命名为subImages,并将图像重命名为mainImage,以保证清晰。但它仍然应该有效。

==================================

它是你的厨房实体,你需要这样才能保持正确的事情:

// Note that your are only passing one image at a time to argument is $image not $images
public function addImage(\PWD\WebsiteBundle\Entity\KitchenImage $kitchenImage)
{
    $this->images[] = $kitchenImage;
    $kitchenImage->setKitchen($this);  // *** Need this for persisting
    return $this;
}

=========================================

当你经历一个故障排除过程只是意识到基本问题完全不同时,这总是很有趣。您需要了解文件上传的工作原理,不仅仅是在Symfony / Doctrine中,而是在Web上。

有了一个新项目,请仔细阅读并实施:

http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html

http://symfony.com/doc/current/reference/forms/types/file.html

一旦您了解了如何上传文件(即图像)以及如何存储它们(数据库中的路径,文件本身位于Web服务器上的某个位置),您就可以回到厨房用品并正确处理图像。一旦你这样做,只需让你的主厨房图像工作,然后添加一组子图像。