unclecheese/silverstripe-dropzone

Files uploaded in front end form do not attach to dataobject.

Closed this issue · 10 comments

This plugin is really great, but I have noticed that if included on a front end form that does not directly link into a dataobject, the files get uploaded but do not get attached to the correct dataobject.

So, the form is pretty basic, all working and submitting, except for the file uploads.

here is the submission code:

public function doOrderForm($data, $form) {

    $submission = new OrderSubmission();

    $form->saveInto($submission);

    $submission->write();

    if(isset($config->newsletterMessage)){
        $customMessage = $config->newsletterMessage;
        $this->setMessage('Success', $customMessage);
    }else{
        $this->setMessage('Success', 'Thank you for your submission');
    }

    return $this->redirectBack();

}

The form submits into a managed dataobject called "Submissions". the normal Upload Field does this fine, but has no nice interface for drag and dropping the files.

However, the minute that I switch to a FileAttachmentField, the file is submitted but no connection is made to the dataobject many_many.

Thoughts? I would love to use this, but I can't if it doesn't have the right relations.

This should work fine. It certainly does in my testing. Can you show me the OrderSumission object?

Sure, I would really appreciate the help, this is Silverstripe 3.4, if it helps

The Attachments are managed in a gridfield on a second tab, and the order submissions are managed by modeladmin...

  public static $db = array(
        'Service' => 'Text',
        'Level' => 'Text',
        'Grade' => 'Text',
        'WordCount' => 'Text',
        'Delivery' => 'Text',
    'Price' => 'Text',
    //
    'Title' => 'Text',
    'Subject' => 'Text',
    'RefStyle' => 'Text',
    'Question' => 'Text',
    'Sources' => 'Text',
    //
    'FirstName' => 'Text',
    'Surname' => 'Text',
    'Email' => 'Text',
    //
        'Created' => 'Text',
    'Status' => 'Text'
    );

  private static $many_many = array(
        'Attachments' => 'File'
    );

    public static $summary_fields = array(
    'ID',
    'Status',
        'Service',
        'Level',
        'Grade',
        'WordCount',
        'Delivery',
    'Price',
    'FirstName',
    'Surame',
        'Created'
    );

    public function getCMSFields() {


    $fields = parent::getCMSFields();

    // Gallery Area
        $config = GridFieldConfig_RelationEditor::create();

        $config->removeComponentsByType("GridFieldDeleteAction");
        $config->addComponent(new GridFieldDeleteAction());

    $attachmentField = new GridField(
        'Attachments',
                'Attached Files',
        $this->Attachments(),
                $config
    );

EDIT: I can send the full file if you need it, but i am not sure what the rest would have to tell you

Any Ideas?

I don't see any Dropzone fields in your code??

Why are you trying to manage files with a GridField?

I believe I explained that in the first post.

The Dropzone field is used on a separate order form object to show on the front end. But the form needs to save into a model admin for the orders. The Dropzone is supposed to show the files that the person attached when they placed their order.

This set up works fine with the normal upload field.

If it helps, here's the order form code -- it's in the controller of the page type

    public function OrderForm() {
        // Create fields

        $uploadField = new FileAttachmentField(
             $name = 'Attachments',
             $title = 'Upload one or more files (max 10 in total)'
         );

        $uploadField->setView('grid');
        $uploadField->setFolderName('Orders/Uploads/'. date('d-M-Y'));

        $uploadField->setThumbnailHeight(180);
        $uploadField->setThumbnailWidth(180);
        $uploadField->setMultiple(true);
        $uploadField->setAutoProcessQueue(true); // do not upload files until user clicks an upload button
        $uploadField->setMaxFilesize(10); // 10 megabytes. Defaults to PHP's upload_max_filesize ini setting
        $uploadField->setAcceptedFiles(array(
            '.pdf','.doc','.docx',
            '.jpg', '.png', '.txt'
        ));
        $uploadField->setPermissions(array(
            'delete' => false,
            'detach' => true
        ));

        $fields = new FieldList(
            new FieldGroup(
                new HeaderField('Service Detail'),
                new TextField('Service'),
                new TextField('Level'),
                new TextField('Grade'),
                new TextField('WordCount'),
                new TextField('Delivery'),
                new TextField('Price')
            ),
            new FieldGroup(
                new HeaderField('Order Details'),
                new TextField('Title'),
                new TextField('Subject'),
                new TextField('RefStyle', 'Referencing Style'),
                $uploadField,
                new TextareaField('Question', 'Essay Question Details'),
                new TextareaField('Sources', 'Required Sources')

            ),
            new FieldGroup(
                new HeaderField('Your Details'),
                new TextField('FirstName', 'First Name'),
                new TextField('Surname', 'Surname'),
                new EmailField('Email'),
                new HiddenField('Status', '', 'Ordered')
            )
        );

        // Create actions
        $actions = new FieldList(
            new FormAction('doOrderForm', 'Order Now')
        );

        $validator = new RequiredFields(
            'Name', 'Email', 'Subject','Title', 'RefStyle', 'Question', 'Sources'
        );
        $form = new Form( $this, 'OrderForm', $fields, $actions, $validator );

        if($startData = Session::get('OrderStartData')) {
        $form->loadDataFrom($startData);
        }

        return $form;
    }
    //Submission
    public function doOrderForm($data, $form) {

        $submission = new OrderSubmission();

        $form->saveInto($submission);

        $submission->write();

        if(isset($config->newsletterMessage)){
            $customMessage = $config->newsletterMessage;
            $this->setMessage('Success', $customMessage);
        }else{
            $this->setMessage('Success', 'Thank you for your submission');
        }

        return $this->redirectBack();

    }

Just for fun, can you try writing the OrderSubmission object before you invoke saveInto, as well as after? That will allow the form to save into a ManyManyList rather than an UnsavedRelationList. Both should work fine, but I'm wondering if that's the issue.

I've figured out the issue, and have resolved it 801d140

The issue has to do with saveInto relying on $form->getRecord() -- a method that doesn't return anything until you call loadDataFrom() on the form. CMS forms always call that method because they're editing forms by nature. In frontend forms, you have to be explicit.

Either way, the form should not require you to invoke loadDataFrom() unnecessarily, so I've made some updates to eliminate the dependency on $form->getRecord().

Here's the code I used for testing, FWIW:

class Page_Controller extends ContentController {

    private static $allowed_actions = [
        'TestForm'
    ];


    public function TestForm()
    {
        return Form::create(
            $this,
            'TestForm',
            FieldList::create(
                TextField::create('Title'),
                FileAttachmentField::create('Attachments')
            ),
            FieldList::create(
                FormAction::create('doTest','Test')
            )
        );
    }

    public function doTest($data, $form)
    {
        $order = new Order();
        $form->saveInto($order);
        $order->write();

        $form->sessionMessage('Yay','good');
        return $this->redirectBack();
    }
}

Let me know how that works for you.

Alrighty, thank you, i will test that in the next couple hours and let you know how i get on :)

Thank you very much for your patience, your fix works perfect as far as I can tell :)

EDIT :: is everything else working okay in the CMS? just making sure i didn't make you break everything

Working in the CMS.

Can't understate the need for functional tests on this module. Someday!