【问题标题】:Symfony2: Using Sonata file field to upload a CSV file and store its content in a Doctrine json_array typeSymfony2:使用 Sonata 文件字段上传 CSV 文件并将其内容存储在 Doctrine json_array 类型中
【发布时间】:2016-01-11 09:53:56
【问题描述】:

在 Symfony 项目中,我需要在实体上存储一些表数据,这些数据应该作为 CSV 文档上传到 Sonata admin 中。我的第一个想法是使用 Doctrine2 json_array 数据类型来存储数据,但我惊讶地发现这并不是一件容易的事。

经过一番研究,我发现Symfony\Component\Form\DataTransformerInterface 似乎是将 CSV 文件转换为数组的正确选择。问题是transform($value)方法没有接收到$value参数中上传的文件,所以我坚持这个。

在我拥有的实体管理类中:

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

CSVToArrayTransformer 看起来像这样:

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

有没有更好的方法来获得这个?

【问题讨论】:

    标签: php symfony doctrine-orm sonata-admin


    【解决方案1】:

    如Sonata documentation (Uploading and serving documents)所说,在提交相应的表单后,应该使用prePersist和preUpdate钩子来处理上传的文件。

    使用这样的东西:

    // 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())        
    }
    
    //...
    

    在你的实体中:

    // 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);
    }
    
    //...
    

    希望这会有所帮助。

    【讨论】:

    • 我读过那本食谱收据,但我认为它没有帮助。 prePersist 和 preUpdate 方法无法更改作为参数接收的 $entity 对象。他们只能通过getSomething()使用它所包含的数据来执行额外的任务,但不能使用setSomething()。在该配方中,您使用图像数据来保存图像,这是一个不同的实体。在我的特定情况下,我没有与 CSV 文件关联的实体,我只需要将数据与该管理类控制的同一实体一起保存即可。我找到了解决方案,很快就会发布。谢谢!
    • doc中的例子使用了另一个实体,但是prePersist可以用来设置当前实体的字段。我已经通过添加一个非映射的 $file 来完成文件上传,调用我的上传方法并使用 uploadFile 信息设置实体字段,所有这些都是从 prePersist 钩子完成的。
    • 那么一定有什么不同。我用另一个属性对此进行了测试,没有任何变化。
    • 这样的东西对name属性没有影响:public function prePersist($entity){$entity->setName($entity->getName() . ' CHANGED NAME IN PRE PERSIST');}
    • 您必须在 prePersist 方法的末尾添加一个return $entity,您的字段将被正确设置。您可以将它用于时间戳或其他需要自定义默认值的字段,或者只是为了执行自定义操作以创建新的。您的解决方案是一个完美的选择,它不涉及您的管理类的更改,我也赞成它。但是看看我的,我已经在我的答案中添加了更改,它更精确并且符合您的需要。
    猜你喜欢
    • 1970-01-01
    • 2017-05-04
    • 2016-06-02
    • 2020-11-02
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    相关资源
    最近更新 更多