Shopping : paramétrer la boutique
Lundi 18 mai 2020 18:03
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">×</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.
Par bestmomo
Aucun commentaire