Shopping : paramétrer la boutique

Nous avons dans le précédent article mis en place la structure de l’administration. Nous allons à présent coder le paramétrage de la boutique pour préciser nom, adresse, téléphone, compte bancaire…

Vous pouvez télécharger un ZIP du projet ici.

Les données

Toutes les informations de la boutique sont rassemblées dans la table shops :

Avec la population on a renseigné les champs de façon aléatoire :

Ces données sont utilisées à plusieurs endroits de la boutique.

On a un seul enregistrement parce qu’une seule boutique.

Dans l’administration il faut pouvoir modifier toutes ces valeurs.

Contrôleur et route

On crée un contrôleur :

php artisan make:controller Back\ShopController

On prévoit une méthode edit pour afficher le formulaire :

<?php

namespace App\Http\Controllers\Back;

use App\Http\Controllers\Controller;
use App\Models\Shop;

class ShopController extends Controller
{
    public function edit()
    {
        $shop = Shop::firstOrFail();

        return view('back.shop.edit', compact('shop'));
    }
}

On ajoute la route pour cette méthode :

Route::prefix('admin')->middleware('admin')->namespace('Back')->group(function () {
    ...
    Route::name('shop.edit')->get('boutique', 'ShopController@edit');
});

Des composants

On va créer 3 composants pour simplifier le codage de la vue du formulaire :

php artisan make:component Inputbs4
php artisan make:component Textareabs4
php artisan make:component Checkbox

Inputbs4

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Inputbs4 extends Component
{
    public $name;
    public $type;
    public $label;
    public $required;
    public $autofocus;
    public $value;

    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($name, $type, $label, $value = '', $required = false, $autofocus = false)
    {
        $this->name = $name;
        $this->type = $type;
        $this->label = $label;
        $this->value = $value;
        $this->required = $required;
        $this->autofocus = $autofocus;
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.inputbs4');
    }
}
<div class="form-group">
  <label for="{{ $name }}">{{ $label }}</label>
  <input 
    id="{{ $name }}" 
    type="{{ $type }}" 
    class="form-control{{ $errors->has($name) ? ' is-invalid' : '' }}"
    name="{{ $name }}" 
    value="{{ old($name, isset($value) ? $value : '') }}" 
    {{ $required ? 'required' : ''}} 
    {{ $autofocus ? 'autofocus' : '' }}>
  @if ($errors->has($name))
    <div class="invalid-feedback">
        {{ $errors->first($name) }}
    </div>
  @endif
</div>

Textareabs4

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Textareabs4 extends Component
{
    public $name;
    public $label;
    public $required;
    public $rows;
    public $autofocus;
    public $value;

    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($name, $label, $value = '', $rows = 3, $required = false, $autofocus = false)
    {
        $this->name = $name;
        $this->label = $label;
        $this->value = $value;
        $this->rows = $rows;
        $this->required = $required;
        $this->autofocus = $autofocus;
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.textareabs4');
    }
}
<div class="form-group">
  <label for="{{ $name }}">{{ $label }}</label>
  <textarea 
    class="form-control{{ $errors->has($name) ? ' is-invalid' : '' }}" 
    id="{{ $name }}" 
    name="{{ $name }}" 
    rows="{{ $rows }}" 
    {{ $required ? 'required' : ''}} 
    {{ $autofocus ? 'autofocus' : '' }}>
    {{ old($name, isset($value) ? $value : '') }}
  </textarea>
  @if ($errors->has($name))
    <div class="invalid-feedback">
        {{ $errors->first($name) }}
    </div>
  @endif
</div>

Checkbox

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Checkbox extends Component
{

    public $name;
    public $label;
    public $value;

    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($name, $label, $value = '')
    {
        $this->name = $name;
        $this->label = $label;
        $this->value = $value;
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.checkbox');
    }
}
<div class="form-group">
  <div class="custom-control custom-checkbox">
    <input 
      type="checkbox" 
      class="custom-control-input" 
      id="{{ $name }}" 
      name="{{ $name }}" 
      @if(old($name, $value)) checked @endif>
    <label class="custom-control-label" for="{{ $name }}">{{ $label }}</label>
  </div>
</div>

La vue

On crée la vue pour le formulaire :

Avec ce code qui utilise les composants qu’on a créés :

@extends('back.layout')

@section('main') 
  <div class="container-fluid"> 
    @if(session()->has('alert'))
      <div class="alert alert-success alert-dismissible fade show" role="alert">
        {{ session('alert') }}
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
    @endif
    <div class="row">
      <div class="col-sm-12">
        <div class="card">
        
          <form method="POST" action="#">
            <div class="card-body">
              @method('PUT')
              @csrf

              <div class="card">
                <h5 class="card-header">Identité</h5>
                <div class="card-body">
          
                  <x-inputbs4
                    name="name"
                    type="text"
                    label="Nom"
                    :value="$shop->name"
                  ></x-inputbs4>

                  <x-inputbs4
                    name="address"
                    type="text"
                    label="Adresse"
                    :value="$shop->address"
                  ></x-inputbs4>

                  <x-inputbs4
                    name="email"
                    type="email"
                    label="Email"
                    :value="$shop->email"
                  ></x-inputbs4>
                  
                  <x-inputbs4
                    name="phone"
                    type="text"
                    label="Téléphone"
                    :value="$shop->phone"
                  ></x-inputbs4>

                  <x-inputbs4
                    name="facebook"
                    type="text"
                    label="Facebook"
                    :value="$shop->facebook"
                  ></x-inputbs4>

                </div>
              </div>

              <div class="card">
                <h5 class="card-header">Banque</h5>
                <div class="card-body">
          
                  <x-inputbs4
                    name="holder"
                    type="text"
                    label="Titulaire"
                    :value="$shop->holder"
                  ></x-inputbs4>

                  <x-inputbs4
                    name="bank"
                    type="text"
                    label="Nom"
                    :value="$shop->bank"
                  ></x-inputbs4>

                  <x-inputbs4
                    name="bank_address"
                    type="text"
                    label="Adresse"
                    :value="$shop->bank_address"
                  ></x-inputbs4>

                  <x-inputbs4
                    name="bic"
                    type="text"
                    label="BIC"
                    :value="$shop->bic"
                  ></x-inputbs4>

                  <x-inputbs4
                    name="iban"
                    type="text"
                    label="IBAN"
                    :value="$shop->iban"
                  ></x-inputbs4>

                </div>
              </div>

              <div class="card">
                <h5 class="card-header">Accueil</h5>
                <div class="card-body">
          
                  <x-inputbs4
                    name="home"
                    type="text"
                    label="Titre"
                    :value="$shop->home"
                  ></x-inputbs4>

                  <x-textareabs4
                    name="home_infos"
                    label="Informations générales"
                    :value="$shop->home_infos"
                  ></x-textareabs4>

                  <x-textareabs4
                    name="home_shipping"
                    label="Frais d'expédition"
                    :value="$shop->home_shipping"
                  ></x-textareabs4>

                </div>
              </div>

              <div class="card">
                <h5 class="card-header">Facturation</h5>
                <div class="card-body">

                  <x-checkbox
                    name="invoice"
                    label="Activation de la facturation"
                    :value="$shop->invoice"
                  ></x-checkbox>
                  
                </div>
              </div>

              <div class="card">
                <h5 class="card-header">Modes de paiement acceptés</h5>
                <div class="card-body">

                  <x-checkbox
                    name="card"
                    label="Carte bancaire"
                    :value="$shop->card"
                  ></x-checkbox>
                  
                  <x-checkbox
                    name="transfer"
                    label="Virement"
                    :value="$shop->transfer"
                  ></x-checkbox>
                  
                  <x-checkbox
                    name="check"
                    label="Chèque"
                    :value="$shop->check"
                  ></x-checkbox>
                  
                  <x-checkbox
                    name="mandat"
                    label="Mandat administratif"
                    :value="$shop->mandat"
                  ></x-checkbox>
                
                </div>
              </div>

              <div class="form-group row mb-0">
                <div class="col-md-12">
                   <button type="submit" class="btn btn-primary">Enregistrer</button>
                </div>
              </div>
              
            </div>            
          </form>

        </div>
      </div>
    </div>
  </div>
@endsection

On ajoute le titre dans config.titles :

return [

    ...

    'shop' => [
        'edit' => 'Gestion de la boutique',
    ],
];

Maintenant avec l’url ../admin/boutique on a le formulaire avec plusieurs zones.

L’identité de la boutique :

Les informations bancaires :

Les textes pour la page d’accueil :

Les options :

Le menu

Il nous faut compléter le menu pour accéder à ce formulaire (back.layout) :

<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">

  ...

  <li class="nav-item has-treeview {{ menuOpen(
        'shop.edit'
    ) }}">
    <a href="#" class="nav-link {{ currentRouteActive(
        'shop.edit'
      ) }}">
      <i class="nav-icon fas fa-cogs"></i>
      <p>
        Administration
        <i class="right fas fa-angle-left"></i>
      </p>
    </a>
    <ul class="nav nav-treeview">

      <x-menu-item :href="route('shop.edit')" :sub=true :active="currentRouteActive('shop.edit', 'shop.update')">
        Boutique
      </x-menu-item>

    </ul>
  </li>
</ul>

On prévoit un menu déroulant nommé Administration dans lequel on mettra tous les réglages, pour le moment juste la boutique :

La validation

Pour la soumission du formulaire on va avoir une validation de tous les champs, et il sont nombreux ! On passe par une requête de formulaire :

php artisan make:request ShopRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ShopRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required|string|max:255',
            'address' => 'required|string|max:255',
            'holder' => 'required|string|max:255',
            'email' => 'required|string|email|max:255',
            'bic' => 'required|regex:/^[a-z]{6}[0-9a-z]{2}([0-9a-z]{3})?\z/i',
            'iban' => 'required|regex:^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}^',
            'bank' => 'required|string|max:255',
            'bank_address' => 'required|string|max:255',
            'phone' => 'required|string|max:25',
            'facebook' => 'required|url|max:255',
            'home' => 'required|string|max:255',
            'home_infos' => 'required|string',
            'home_shipping' => 'required|string',
        ];
    }
}

Il y a deux champs (bic et iban) qui nécessitent un traitement particulier avec un regex. D’ailleurs les valeurs générées par la population ne passeront certainement pas la validation. Pour vos tests vous pouvez utiliser :

  • IBAN : FR7612548029989876543210917 (celui de la banque AXA)
  • BIC : CMCIFRPP (celui du CIC)

Contrôleur et route

Pour la mise à jour on ajoute la méthode update dans le contrôleur ShopController :

use App\Http\Requests\ShopRequest;

...

public function update(ShopRequest $request)
{
    $request->merge([
        'invoice' => $request->has('invoice'),
        'card' => $request->has('card'),
        'transfer' => $request->has('transfer'),
        'check' => $request->has('check'),
        'mandat' => $request->has('mandat'),
    ]);        

    Shop::firstOrFail()->update($request->all());

    return back()->with('alert', config('messages.shopupdated'));
}

On ajoute le message dans config.messages :

return [
    ...
    'shopupdated' => 'La boutique a bien été mise à jour.',
];

Et la route :

Route::prefix('admin')->middleware('admin')->namespace('Back')->group(function () {
    ...
    Route::name('shop.update')->put('boutique', 'ShopController@update');
});

On ajoute la route pour le menu dans back.layout :

<li class="nav-item has-treeview {{ menuOpen(
      'shop.edit',
      'shop.update'
  ) }}">
  <a href="#" class="nav-link {{ currentRouteActive(
      'shop.edit',
      'shop.update'
    ) }}">

A la soumission si la validation passe la base est mise à jour et on a le message au retour :

Conclusion

On peut désormais modifier tous les paramètres de la boutique à partir de l’administration. Dans le prochain article on continuera le paramétrage.

Print Friendly, PDF & Email

Laisser un commentaire