Il Controller
Come già detto, il nostro Controller RESTful conterrà solo i tre metodi necessari index() , store() e destroy() , che serviranno rispettivamente per mostrare, caricare/memorizzare e cancellare le immagini.
Operazioni preliminari
Per prima cosa importiamo le classi che ci servono:
1 2 3 4 5 |
use App\Picture; use Croppa; use File; use FileUpload; use Illuminate\Http\Request; |
Definiamo inoltre una cartella, dove salvare le nostre immagini, come proprietà del nostro Controller:
1 |
public $folder = '/uploads/'; // add slashes for better url handling |
Per un progetto piccolo va bene così, altrimenti è consigliabile creare un file di configurazione dove definire la nostra cartella. Le immagini verranno salvate in /public/uploads .
Creiamo quindi il nostro primo metodo.
Il metodo index()
Analizziamo l’esempio di “Basic Plus UI” di Blueimp con gli strumenti di sviluppo di Chrome: notiamo che ciascuna immagine caricata, per poter essere mostrata correttamente nella tabella, viene restituita in formato JSON.
1 2 3 4 5 6 7 8 9 10 11 |
{"files": [{ "url":"http://jquery-file-upload.appspot.com/image%2Fjpeg/2180020089/Chrysanthemum.jpg", "thumbnailUrl":"http://jquery-file-upload.appspot.com/image%2Fjpeg/2180020089/Chrysanthemum.jpg.80x80.jpg", "name":"Chrysanthemum.jpg", "type":"image/jpeg", "size":879394, "deleteUrl":"http://jquery-file-upload.appspot.com/image%2Fjpeg/2180020089/Chrysanthemum.jpg", "deleteType":"DELETE" }] } |
Prendiamo quindi questo modello per costruire il nostro JSON con i dati prelevati dal database, così da mostrare all’apertura della pagina le immagini già caricate in precedenza (se ci sono). Alcuni campi ( name e url ) possiamo ottenerli direttamente dal database, altri invece li dovremo comporre noi (in particolare size , thumbnailUrl , deleteType e deleteUrl). Ecco il codice completo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public function index() { // get all pictures $pictures = Picture::all(); // add properties to pictures $pictures->map(function ($picture) { $picture['size'] = File::size(public_path($picture['url'])); $picture['thumbnailUrl'] = Croppa::url($picture['url'], 80, 80, ['resize']); // create a 80x80 thumbnail on the fly $picture['deleteType'] = 'DELETE'; $picture['deleteUrl'] = route('pictures.destroy', $picture->id); return $picture; }); // show all pictures return response()->json(['files' => $pictures]); } |
Passiamo quindi al secondo metodo.
Il metodo store()
Questo è il metodo più complesso: per comodità, ho accorpato sia l’upload che il salvataggio su database. Il grosso è stato copiato dall’esempio presente su gargron/fileupload, che però è incompleto e necessita di qualche aggiustamento per restituire i dati corretti. In più ho aggiunto qualche script personalizzato (ad es. per creare la cartella /public/upload nel caso in cui non sia presente). Il codice completo è questo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
public function store(Request $request) { // create upload path if it does not exist $path = public_path($this->folder); if(!File::exists($path)) { File::makeDirectory($path); }; // Simple validation (max file size 2MB and only two allowed mime types) $validator = new FileUpload\Validator\Simple('2M', ['image/png', 'image/jpg', 'image/jpeg']); // Simple path resolver, where uploads will be put $pathresolver = new FileUpload\PathResolver\Simple($path); // The machine's filesystem $filesystem = new FileUpload\FileSystem\Simple(); // FileUploader itself $fileupload = new FileUpload\FileUpload($_FILES['files'], $_SERVER); $slugGenerator = new FileUpload\FileNameGenerator\Slug(); // Adding it all together. Note that you can use multiple validators or none at all $fileupload->setPathResolver($pathresolver); $fileupload->setFileSystem($filesystem); $fileupload->addValidator($validator); $fileupload->setFileNameGenerator($slugGenerator); // Doing the deed list($files, $headers) = $fileupload->processAll(); // Outputting it, for example like this foreach($headers as $header => $value) { header($header . ': ' . $value); } foreach($files as $file){ //Remember to check if the upload was completed if ($file->completed) { // set some data $filename = $file->getFilename(); $url = $this->folder . $filename; // save data $picture = Picture::create([ 'name' => $filename, 'url' => $this->folder . $filename, ]); // prepare response $data[] = [ 'size' => $file->size, 'name' => $filename, 'url' => $url, 'thumbnailUrl' => Croppa::url($url, 80, 80, ['resize']), // create a 80x80 thumbnail on the fly 'deleteType' => 'DELETE', 'deleteUrl' => route('pictures.destroy', $picture->id), ]; // output uploaded file response return response()->json(['files' => $data]); } } // errors, no uploaded file return response()->json(['files' => $files]); } |
Infine, l’ultimo metodo.
Il metodo destroy()
Cancelliamo sia l’immagine fisica (e le relative miniature – tutto in automatico grazie a Croppa!) che il record sul database:
1 2 3 4 5 6 |
public function destroy(Picture $picture) { Croppa::delete($picture->url); // delete file and thumbnail(s) $picture->delete(); // delete db record return response()->json([$picture->url]); } |
A questo punto il nostro script è completo e possiamo testarlo.