2
votes

Okay, this gets a little convoluted, so bear with me. I'll try and keep it clear and concise.

I'm using Symfony2's very nice form builder system for simple crud, but the basic file upload element doesn't quite meet my needs, so I want to extend it by adding a thumbnail preview, and some other niceties.

Reading this, I found that I can create my own custom template block for rendering file elements:

http://symfony.com/doc/master/cookbook/form/form_customization.html#twig

Which is really cool, and seems to be working perfectly. However, I'm storing the path for my file upload in a separate attribute in the entity, based on this:

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

So, I need some way for the template to access the path field. I created a custom FileType class like this:

<?php

namespace TechPeople\InvoiceBundle\Component\Form\Type;

use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;

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

class FileType extends SymfonyFileType {
    /**
     * {@inheritdoc}
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars = array_replace($view->vars, array(
            'type'  => 'file',
            'value' => '',
            'path' => $options['path'],
        ));
    }
}

And then I passed the file path into the form builder like this:

<?php

namespace TechPeople\InvoiceBundle\Form;

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

class InvoiceType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        echo 'test';
        $builder
            ->add('month')
            ->add('year')
            ->add('expenses')
            ->add('due')
            ->add('paid')
            ->add('created')
            ->add('expense_amount', 'money')
            ->add('total_amount', 'money')
            ->add('attachment', 'file', array('path'=>$options['data']->getAttachmentPath()))
            ->add('vendor')
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TechPeople\InvoiceBundle\Entity\Invoice'
        ));
    }

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

Well, that seemed pretty groovy, but then I get this error loading the form:

The option "path" does not exist. Known options are: "attr", "block_name", "by_reference", "cascade_validation", "compound", "constraints", "csrf_field_name", "csrf_protection", "csrf_provider", "data", "data_class", "disabled", "empty_data", "error_bubbling", "error_mapping", "extra_fields_message", "intention", "invalid_message", "invalid_message_parameters", "label", "label_attr", "mapped", "max_length", "pattern", "post_max_size_message", "property_path", "read_only", "required", "translation_domain", "trim", "validation_constraint", "validation_groups", "virtual"
500 Internal Server Error - InvalidOptionsException

So, it looks like there's a list of allowed options somewhere, but I can't find it. Additionally, I'm not 100% sure that the add() method in InvoiceType is passing the options array to the buildView() method in FileType. I'm having trouble tracing the code between these two things.

1
yeah, the allowed options are defined in each type (and its hierarchy): github.com/symfony/Form/blob/master/Extension/Core/Type/… - Florian Klein

1 Answers

2
votes

First of all, once you created your custom class, you should declare it (register it) to be used as file type: http://symfony.com/doc/current/reference/dic_tags.html#form-type

<?php

namespace TechPeople\InvoiceBundle\Component\Form\Type;

use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;

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

class FileType extends SymfonyFileType 
{
/**
 * {@inheritdoc}
 */
public function buildView(FormView $view, FormInterface $form, array $options)
{
    $view->vars = array_replace($view->vars, array(
        'type'  => 'file',
        'value' => '',
        'path' => $options['path'],
    ));
}

/**
 * {@inheritdoc}
 */
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'path' => null,
    ));
}

/**
 * {@inheritdoc}
 * 
 * POTENTIALLY declare it as child of file type.
 */
public function getParent()
{
    return 'file';
}
}