VMC
VMC

Reputation: 1388

Symfony2: Using Sonata file field to upload a CSV file and store its content in a Doctrine json_array type

In a Symfony project I need to store some table data on an entity, data which is supposed to be uploaded as a CSV document in Sonata admin. My first thought was to use the Doctrine2 json_array data type to store the data, but I was surprised to find out that it's not such a easy task.

After some research I found the Symfony\Component\Form\DataTransformerInterface which seemed to be the right choice to transform the CSV file into an array. The problem is that the transform($value) method is not receiving the uploaded file in $value parameter, so I'm stuck with this.

In the entity admin class I have:

$formMapper
    [...]
    ->add($formMapper->create('discounts', 'file', array(
        'required' => false,
        'data_class' => null
      ))
      ->addViewTransformer(new CSVToArrayTransformer()))

where CSVToArrayTransformer looks like this:

class CSVToArrayTransformer implements DataTransformerInterface
{
   public function transform($csvFile){
       // here should take place the csv to array transformation, but $csvFile is null
   }
}

Is there a better method to obtain this?

Upvotes: 2

Views: 2196

Answers (1)

chalasr
chalasr

Reputation: 13167

As stated by Sonata documentation (Uploading and serving documents), you should use the prePersist and preUpdate hooks to deal with the uploaded file after submitting the corresponding form.

Use something like this :

// Admin class

//...

protected function configureFormFields(FormMapper $formMapper)
    $formMapper
        //...
        ->add('file', 'file', array(
            'required' => false,
            'data_class' => null,
        ))
        //...
    ;
}

// Called on submit create form.
public function prePersist($entity)
{
    $this->manageFileUpload($entity);

    return $entity;
}

// Called on submit edit form.
public function preUpdate($entity)
{
    $this->manageFileUpload($entity);

    return $entity;
}

protected function manageFileUpload($entity)
{
    $entity->convertUploadedCsvToArray($entity->getFile())        
}

//...

And in your entity :

// Entity

//...

// Unmapped property used for file upload
protected $file;

/**
 * Sets file.
 *
 * @param UploadedFile $file
 */
public function setFile(UploadedFile $file = null)
{
    $this->file = $file;
}

/**
 * Get file.
 *
 * @return UploadedFile
 */
public function getFile()
{
    return $this->file;
}

/**
 * Upload attachment file
 */
public function convertUploadedCsvToArray()
{
    if (null === $this->getFile()) {
        return;
    }

    $this->getFile()->move('youruploadpath', $this->getFile()->getClientOriginalName());

    // Do your logic with the csv file here
    $transformer = new CsvDataTransformer();
    $discounts = $transformer->transform($this->getFile());

    // Set the field using result of parsing.
    $this->setDiscounts($discounts);

    // Empty the 
    $this->setFile(null);
}

//...

Hope this helps.

Upvotes: 2

Related Questions