Créer une galerie d'image

Si comme moi vous n'aimez pas perdre 5 minutes de votre temps pour vous inscrire sur un site alors pensez que vos visiteurs également n'aiment pas cela! 😁

Je parie que vous faîtes partis de cette catergorie de personne qui sont toujours obliger de regarder un tutoriel pour se souvenir comment uploader un fichier, n'est-ce pas ? ;-)

Si la réponse est oui alors vous êtes tomber au bon endroit.

Dans ce tutoriel nous allons voir comment uploader non pas un... deux... trois... mais plusieurs fichiers à la fois !

Nous allons utiliser un peu de JavaScript en utilisant la librairie dropzone qui va nous permettre de mettre en place une zone (plutôt sympa) pour glissser/déposer nos fichiers.

Dropzone zone de glissement/déposer

Afin d'illustrer notre exemple dans un cas concret, nous allons créer une galerie d'image! Une sorte d'hebergeur privé pour vos images! :D

Pour ce tutoriel nous allons créer un nouveau projet Laravel (mais vous pouvez prendre un projet déjà existant). Si vous avez installer Laravel globalement sur votre machine :

laravel new larafile

Sinon :

composer create-project --prefer-dist laravel/laravel larafile

Vous l'aurez deviner, notre projet s'appellera larafile (oui je sais, je ne me prends jamais la tête !).

Base de données & Migration

Une fois votre projet crée; allez dans le fichier .env et configurez votre base de données :

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=larafile
DB_USERNAME=homestead
DB_PASSWORD=secret

Nous allons créer par la suite un Model Gallery ainsi que sa migration et un controller GalleryController:

php artisan make:model Gallery -mc

Création d'un Modèle

Ici j'ai utilisé artisan pour créer le Modèle, la migration ainsi que le contrôleur en une seule manipulation avec le paramètre mc sans les ressources. Mais si vous voulez les ressources vous pouvez mettre -mr à la place de -mc.

Ouvrez le fichier de la migration database / migrations / xxx_create_galleries_table.php et ajoutez dans la methode up() :

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateGalleriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('galleries', function (Blueprint $table) {
            $table->increments('id');
            $table->string('file');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('galleries');
    }
}

Ouvrez ensuite le fichier modèle app / Gallery.php et ajouter la propriété protégée $guarded :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Gallery extends Model
{
    protected $guarded = [];
}

Comme il n'y a qu'un seul enregistrement j'ai tout simplement mis un $guarded mais si vous préférez le $fillable :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Gallery extends Model
{
    protected $fillable = ['file'];
}

Maintenant vous pouvez lancer la migration.

php artisan migrate

Si comme moi vous êtes sur MariaDB ou que vous obtenez ce message d'erreur lors de la migration :

 [Illuminate\Database\QueryException]                                                                
 SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length  
  is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))
 
 [PDOException]                                                                                      
 SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length  
   is 767 bytes       

Échec de la migration

Allez dans le fichier provider app / Providers / AppServiceProvider.php et modifiez-le comme ceci :

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Relancez la migration, si cela ne fonctionne pas, vous pouvez supprimer manuellement la table migration et users (si vous l'avez laisser) et refaîtes les manipulations ou sinon faites un :

php artisan migrate:fresh

php artisan migrate:fresh" class="img-fluid

Le formulaire d'envoi d'image

Créez un fichier dans le dossier resources / views . Pour ma part ça sera gallery.blade.php.

Et ajoutez ce code (je n'ai pas fait d'effort sur le design ^-^").

<!doctype html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Galerie d'image</title>

    <!-- Fonts -->
    <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">


    <!-- Dropzone -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.2.0/min/dropzone.min.css" />

</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarsExampleDefault">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
                <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="#">Link</a>
            </li>
            <li class="nav-item">
                <a class="nav-link disabled" href="#">Disabled</a>
            </li>
            <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="http://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
                <div class="dropdown-menu" aria-labelledby="dropdown01">
                    <a class="dropdown-item" href="#">Action</a>
                    <a class="dropdown-item" href="#">Another action</a>
                    <a class="dropdown-item" href="#">Something else here</a>
                </div>
            </li>
        </ul>
        <form class="form-inline my-2 my-lg-0">
            <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
            <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
        </form>
    </div>
</nav>

<main role="main" class="container" style="margin-top: 7%">
    <form id="addImageGallery" action="{{ url("gallery") }}" method="POST" class="dropzone container">
        {{ csrf_field() }}
    </form>
</main>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.2.0/dropzone.js"></script>
<script>
    Dropzone.options.addImageGallery = {
        paramName: 'image',
        maxFilesize: 3,
        acceptedFiles: '.jpg, .jpeg, .png, .gif, .bmp'
    }
</script>
</body>
</html>

Alors ici j'ai ajouté des CDN pour les fichiers de CSS et de JS de dropeone ainsi de boostrap (pour avoir une jolie petite mise en forme).

Puis j'ai ouvert une balise form et j'ai mis comme attribut class dropzone afin que le formulaire se transforme en zone pour glisser/déposer nos images.

J'ai également mis un attribut id qui a pour nom addImageGallery ainsi qu'une balise script qui est directement relier à cet id.

Dans cette balise script j'ai procédé à des modifications comme ceci :

  • paramName : Correspond au nom de l'input file, ici la requête sera request('image').
  • maxFilesize : La taille maximun de l'image en Mo
  • acceptedFiles : les fichiers acceptés.

Par défaut le nom de la requête est file (request('file')) mais ici je l'ai modifié pour image.

Ici le JavaScript nous facilite avec une methode de validation mais cela n'est pas vraiment une sécurité fiable, le mieux serait de toujours utiliser la methode de validation de Laravel (nous le verrons dans l'étape du contrôleur).

La route

Nous allons simplement créer deux routes : celle de la vue et celle du traitement des images.

Route::get('gallery', 'GalleryController@create');
Route::post('gallery', 'GalleryController@store');

php artisan route:list

Vous pouvez également directment faire ceci pour gagner du temps :

Route::resource('gallery', 'GalleryController');

Mais je n'apprécie guère les routes avec des resources; cela créer des routes qui ne seront sans doute jamais utiliser (ce qui veut dire qu'il y aura des liens sans contenus sur votre site et évitez cela!).

Si vous n'utilisez pas de vertualhost faîtes un

php artisan serve

Et allez sur : http://localhost:8000/gallery Maintenant vous pouvez vous amuser à uploader des images ;-)

Le contrôleur

Maintenant nous allons passer au chose sérieuse! LanceZ l'outil de dévéloppeur de votre navigateur (CTRL + ALT + I) et allez das l'onglet "Network".

Outil du développeur

Allez dans le dossier public / créez un dossier uploads puis dans le fichier app / Http / Controllers / GalleryController.php ajoputez tout ce code:

<?php

namespace App\Http\Controllers;

use App\Gallery;
use Illuminate\Http\Request;

class GalleryController extends Controller
{
    public function create(){
        return view('gallery');
    }

    public function store(Request $request){
        $this->validate($request, [
            'image' => 'required|mimes:jpg,jpeg,png,gif,bmp'
        ]);

        $file = $request->file('image');
        $name = time() .'-'. $file->getClientOriginalName();
        $file->move("uploads/", $name);
        Gallery::create([
            'file' => "/uploads/{$name}",
        ]);
        return "Images ajoutées avec succès!";
    }
}

Normalement si tout se passe bien vous obtiendrez quelque chose de ce genre.. :

Larafile -images ajoutées avec succès

Et dans le dossier public / uploads

Larafile - upload d'image

Comme vous pouvez le constater le code est très simple. Vous pouvez l'améliorer à votre guise!

Voir l'exemple