2

I'm struggling with symfony3 forms and the CollectionType class:

I have a page with several complex forms. I do not use any database (the validated forms are sent to a foreign REST-service)

Now let's say I have an entity object for my request called "ProductService":

class ProductService
{
    /** @var string */
    private $msg;

    /** @var array*/
    private $products
}

And a class ProductServiceType to render the form:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('products', CollectionType::class, [
            'entry_type'   => ProductType::class,
        ])
        ->add('msg' [...]);
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'data_class' => ProductService::class,
    ]);
}

With this setup, everything works like a charm, all products will be added in the products array of my entity. The problem is, i want $products to be a SplObjectStorage-object:

class ProductService
{
    /** @var string */
    private $msg;

    /** @var SplObjectStorage */
    private $products
}

If i set it to this and attach an empty object into it, symfony can't render the form any more. It throws following error: Warning: SplObjectStorage::offsetExists() expects parameter 1 to be object, string given

So, can anybody tell me, how to handle the collectionType in an entity when NOT using doctrine and orm? Is the only possibility using arrays, or is there any documentation for this case, i did not find? (I'm still wondering how symfony calls offsetExists, there must be someting implemented to handle SplObjectStorage, or am i wrong?)

j0nnybrav0
  • 123
  • 2
  • 11

1 Answers1

1

I believe your error is caused because a form collection has not been implemented to handle SplObjectStorage as you would expect. You can create an issue for it at the symfony repository.

The error is caused when symfony is trying to populate the form collection by reading your products from ProductService this way:

$products = $productService->getProducts();
$products->offsetExists(0); //here is the error.

because it expects any storage that implements ArrayAccess will be read this way, but for SplObjectStorage this is not the case.

Form elements have a setting property_path link which you can take advantage to work around your issue.

My solution is to use this setting and return return an array to populate your collection:

$builder
        ->add('products', CollectionType::class, [
            'entry_type'   => ProductType::class,
            'property_path' => 'productsArray'
        ])

class ProductService
{

... 
public function getProductsArray() {
    $prArray= [];
    foreach ($this->products as $value) {
        $prArray[] = $value;
    }
    return $prArray;
}

This way you can populate your form collection using the array produced.

Another solution I think would be to use a data transformer. Hope this helps

Jannes Botis
  • 11,154
  • 3
  • 21
  • 39
  • Wow, you made my day, Mr. Botis :) that really seems to be a nice solution! I will try it the following days and give an answer. Thank you very much – j0nnybrav0 Nov 21 '17 at 07:55
  • Hi Jannes, I just implemented your solution and it works. Thank you very much! – j0nnybrav0 Nov 23 '17 at 09:00