silverstripe / silverstripe-assets

Silverstripe Assets component
BSD 3-Clause "New" or "Revised" License
9 stars 67 forks source link

Unable to save File to database from front end form in SilverStripe 4 #184

Open nickspiel opened 8 years ago

nickspiel commented 8 years ago

I have a form that is posting data to a controller via ajax.

// Create new upload instance
$upload = Upload::create();

// Create new file instance
$file = File::create();

// Upload the file
$upload->loadIntoFile($fileData, $file, $this->folderName);

// Get the file from the Upload
$uploadedFile = $upload->getFile();

// Get the file from the Upload
$write = $uploadedFile->write();

The image is uploaded successfully but the File is not written to the Files table.

No errors are reported.

Update: I have tested the same code in SS3 and the File is uploaded successfully and written to the DB.

nickspiel commented 8 years ago

@sminnee I have tested this in v3 and it works. This should probably be tagged as affects/v4.

sminnee commented 8 years ago

Doh, fat thumbs on my part. Thanks for the clarification.

tractorcow commented 8 years ago

I think the problem could be initial writes (on the live stage) are written to that same stage, live only.

We could add some logic so that versioned records are always written to stage, if they are being created for the first time (even if current stage is live).

nickspiel commented 8 years ago

Is this a similar issue to https://github.com/silverstripe/silverstripe-framework/issues/6048#issuecomment-248773526? ie the file is not published when uploaded? Is there a workaround I can implement for now?

tractorcow commented 8 years ago

Follow up at https://github.com/silverstripe/silverstripe-framework/issues/6059. :D

ghost commented 6 years ago

Hello guys, I'm stuck in a similar issue like @nickspiel 's case. Basically, I got a front-end form that must send files via ajax calls to a page controller. The files must be saved and related to a Member/DataExtension that implements a File::class/$many_many property/relation (in order to save and associate them to every CMS user).

Here's my approach:

My Member Extension

[...]
/**
 * Classe Utente - Estensione
 */
class UtenteExtension extends DataExtension
{
    // Dichiarazione Proprietà
    private static $many_many = [
        'AllegatiUpload' => File::class, // this field should save users file uploads
        [...]
    ];
    private static $owns = [
        'AllegatiUpload',
        [...]
    ];
[...]

The Controller involved:

use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\ErrorPage;
use SilverStripe\Assets\Folder;
use SilverStripe\Assets\File;
use SilverStripe\Assets\Upload;
use SilverStripe\Security;
use SilverStripe\Security\Group;
use SilverStripe\Assets\Storage\AssetStore;

/**
 * Classe Controller Utente - Dashboard
 */
class UtenteDashboardController extends PageController
{
    // Dichiarazione Proprietà
    private static $allowed_actions = [
        'carica'
    ];

    /**
    * Funzione gestione validazione ed invio form caricamento
    * @param  HTTPRequest $request Richiesta HTTP
    * @return HTTPResponse Risposta HTTP
    */
    public function carica(SS_HTTPRequest $request) {
        if (!$request->isAjax()) {
            return ErrorPage::response_for(404);
        } else if (!$request->isPOST()) {
            return $this->httpError(400, 'Metodo POST richiesto');
        } else {
            $documento = $request->postVar('documento'); // File data sent by FormData JS API

            if (!isset($documento)) {
                return $this->httpError(500, 'Dati richiesti mancanti');
            } else {
                // User check
                $utente = Security::getCurrentUser();

                if ($utente->inGroup(Group::get()->filter('Code', 'clienti')->first()->ID)) {
                    // File uploading
                    $cartellaUpload = 'clienti/'. strtolower($utente->Surname) .'/uploads';

                    Folder::find_or_make($cartellaUpload);

                    // I tried with the official guide approach, with this line - with no results
                    //$utente->AllegatiUpload()->setFromLocalFile($cartellaUpload, documento, AssetStore::CONFLICT_OVERWRITE);
                     // Then I tried with this approach
                    $file = File::create();
                    $upload = Upload::create();

                    $upload->loadIntoFile($documento, $file, $cartellaUpload);

                    // Upload check
                    if ($upload->isError()) {
                        return $this->httpError(400, 'Errore di caricamento file');
                    } else {
                        // Relate the file to the destinaion user field
                        $utente->{'AllegatiUpload.ID'} = $upload->getFile()->ID;
                        // Update user
                        $utente->write(); 

                        return new HTTPResponse;
                    }
                } else {
                    return $this->httpError(401, 'Utente non abilitato');
                }
            }
        }
    }
}

This results in no DB File table written as well as no file uploaded in the designed assets destination folder. Furthermore, no excetptions are thrown - it returns the HTTPResponse so I presume that the code beign run with no errors?. In any case, here's the request result: screen shot 2018-05-21 at 12 25 29 screen shot 2018-05-21 at 12 25 08

At this time I don't understand what I'm missing here.

Can anyone help me to catch the error?

Thanks in advance.

ghost commented 6 years ago

Seems that my problem was related to a wrongly injected dependency:

use SilverStripe\Security;

By changing it to point to the correct controller:

use SilverStripe\Security\Security;

the files start to beign uploaded as expected.