Commit 98221b76 authored by Sylvain's avatar Sylvain

Ajout d'un module example « small »

parent f5b74bbe
......@@ -171,6 +171,23 @@ Après avoir configurer l'accès à la base de données, il est temps de créer
php artisan migrate --seed
```
## Modules
Vous pouvez créer votre application sous forme de modules. Un exemple de module se trouve dans le dossier /Modules
Pour permettre l'auto-chargement des classes des modules, il est neccessaire le modifier le fichier `composer.json` comme ci-dessous :
```json
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Modules\\": "Modules/"
}
}
}
```
## Security
......
......@@ -33,6 +33,7 @@ npm install --save-dev @babel/core@7.12.16
npm install --save-dev @babel/preset-env@7.12.16
npm install --save-dev @tailwindcss/forms@0.2.1
npm install --save-dev @vue/test-utils@1.1.3
npm install --save-dev @vue/composition-api@1.0.0-rc.9
npm install --save-dev sass@1.32.7
npm install --save-dev sass-loader@8.0.2
npm install --save-dev vue-jest@3.0.7
......
<?php
return [
'name' => 'Small',
// Liste des routes vers le module
'menu' => [
'icon' => 'fa fa-magic',
'label' => 'Small',
'route' => 'module.small.index',
]
];
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateModuleSmallConfigTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('module_small_config', function (Blueprint $table) {
$table->id();
$table->string('params1');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('module_small_config');
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateModuleSmallTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('module_smalls', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->unsignedInteger('user_id');
$table->timestamps();
// Contraintes
$table->foreign('user_id')->references('id')->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('module_smalls', function (Blueprint $table) {
$table->dropForeign(['user_id']);
});
Schema::dropIfExists('module_smalls');
}
}
<?php
namespace Modules\Small\Database\Seeders;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model;
class ConfigTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Model::unguard();
// Ajout du menu dans la table de configuration
DB::table('module_small_config')->insert([
'params1' => 'Small',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
]);
}
}
<?php
namespace Modules\Small\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class SmallDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Model::unguard();
$this->call(ConfigTableSeeder::class);
$this->call(SmallsTableSeeder::class);
}
}
<?php
namespace Modules\Small\Database\Seeders;
use Illuminate\Support\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model;
class SmallsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Model::unguard();
DB::table('module_smalls')->insert([
[
'name' => 'Small 1',
'user_id' => 1,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
],
[
'name' => 'Small 2',
'user_id' => 1,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
],
[
'name' => 'Small 3',
'user_id' => 1,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
]
]);
}
}
<?php
namespace Modules\Small\Exports;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Modules\Small\Http\Repositories\SmallRepository;
class SmallExport implements FromCollection, WithHeadings, ShouldAutoSize, WithEvents
{
private $collection;
private $prop_title;
private $prop_description;
private $prop_author;
private $prop_subject;
private $prop_company;
private $sheet_columns;
public function __construct()
{
$this->prop_description = "Export des exemple du module Exemple";
$this->prop_title = "Liste des exemples";
$this->prop_author = "Sylvain";
$this->prop_subject = "Export";
$this->prop_company = "Goldenscarab";
$this->sheet_title = 'Smalls';
$this->sheet_colums = array(
'id' => 'ID',
'name' => 'Nom',
'user.name' => 'Utilisateur',
'created_at' => 'Date'
);
}
/**
* Récupération des données depuis la BDD
* @return Collection La liste des données à exporter
*/
public function collection()
{
$small_repo = new SmallRepository;
return $small_repo->all(array_keys($this->sheet_colums));
}
/**
* Ajout d'une ligne d'entêtes (les titres)
* @return array Les titres
*/
public function headings(): array
{
return array_values($this->sheet_colums);
}
/**
* Configuration de la feuille d'export
* @return array La config
*/
public function registerEvents(): array
{
return [
BeforeExport::class => function(BeforeExport $event) {
// Propriétées du tableau
$event->writer->getProperties()
->setCreator($this->prop_author)
->setLastModifiedBy($this->prop_author)
->setTitle($this->prop_title)
->setSubject($this->prop_subject)
->setCompany($this->prop_company)
->setDescription($this->prop_description);
},
AfterSheet::class => function(AfterSheet $event) {
// Calcul de la zone des titres
$title_end = chr(65 + count($this->sheet_colums) - 1);
$zone_title = sprintf('A1:%s1', $title_end);
// Style des titres
$event->sheet->getDelegate()->getStyle($zone_title)->getFont()->setBold(true);
// Filtre sur les titres
$event->sheet->setAutoFilter($zone_title);
// Volets verrouillés
$event->sheet->freezePane('A2');
// Titre de l'onglet
$event->sheet->setTitle($this->sheet_title);
},
];
}
}
<?php
namespace Modules\Small\Http\Controllers\Api;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Crypt;
use Modules\Small\Models\Small;
use Modules\Small\Http\Repositories\SmallRepository;
class SmallController extends Controller
{
private $small_repo;
public function __construct(SmallRepository $small_repo)
{
$this->small_repo = $small_repo;
}
/**
* Display a listing of the resource.
* @return Response
*/
public function index(Request $request)
{
$sort = $request->get('sort', 'id');
$direction = $request->get('direction', 'asc');
$persmall = $request->get('perpage', 15);
$search = $request->get('search');
$smalls = $this->small_repo->list($sort, $direction, $persmall, $search);
$smalls->load('user');
return response()->json($smalls);
}
/**
* Store a newly created resource in storage.
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
//
}
/**
* Show the specified resource.
* @param int $id
* @return Response
*/
public function show(Request $request, $public_id)
{
$small = $this->small_repo->findOrfail($public_id);
// Retourne avec un cache en secondes
return response()->json($small)->header('Cache-Control', 'max-age=60');
}
/**
* Update the specified resource in storage.
* @param Request $request
* @param int $id
* @return Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
* @param int $id
* @return Response
*/
public function destroy($id)
{
//
}
}
<?php
namespace Modules\Small\Http\Controllers\App;
use Modules\Small\Models\Config;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Redirect;
use Modules\Small\Http\Requests\ConfigStoreRequest;
class ConfigController extends Controller
{
public function index()
{
// Récupération de la config
$config = $config = Config::first();;
$breadcrumb = array(
'Accueil' => route('modulus.dashboard'),
'Modules' => route('modulus.module.index'),
'Small' => null,
'config' => null
);
return view('small::app.config.form')->with([
'title' => '<i class="fa fa-cogs mr-2" aria-hidden="true"></i>Module Small',
'subtitle' => 'Configuration',
'config' => $config,
'breadcrumb' => $breadcrumb
]);
}
public function store(ConfigStoreRequest $request)
{
$config = Config::first();
$config->params1 = $request->get('params1');
$config->save();
Session::flash('success', "Configuration enregistrée avec succès");
return Redirect::route('modulus.module.index');
}
}
<?php
namespace Modules\Small\Http\Controllers\App;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Contracts\Support\Renderable;
use Modules\Small\Exports\SmallExport;
use Modules\Small\Http\Requests\SmallStoreRequest;
use Modules\Small\Http\Repositories\SmallRepository;
class SmallController extends Controller
{
private $small_repo;
public function __construct(SmallRepository $small)
{
$this->small_repo = $small;
// Définition des permissions par méthode
$this->middleware('permission:module-small-read')->only(['index']);
$this->middleware('permission:module-small-create')->only(['create', 'duplicate']);
$this->middleware('permission:module-small-update')->only(['edit']);
$this->middleware('permission:module-small-delete')->only(['destroy']);
view()->share('route_prefix', "module.small");
}
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index()
{
$breadcrumb = array(
'Accueil' => route('modulus.dashboard'),
'Exemples' => null
);
return view('small::app.small.index')->with([
'title' => '<i class="fa fa-magic mr-1" aria-hidden="true"></i>Exemples',
'breadcrumb' => $breadcrumb,
]);
}
/**
* Show the form for creating a new resource.
* @return Renderable
*/
public function create()
{
$small = $this->small_repo->new();
$breadcrumb = array(
'Accueil' => route('modulus.dashboard'),
'Exemples' => route('module.small.index'),
'Ajouter' => null
);
return view('small::app.small.form')->with([
'title' => '<i class="fa fa-magic mr-1" aria-hidden="true"></i>Exemples',
'action' => '<i class="fa fa-plus mr-2"></i>Création',
'breadcrumb' => $breadcrumb,
'item' => $small
]);
}
/**
* Show the form for editing the specified resource.
* @param int $id
* @return Renderable
*/
public function edit($id)
{
$small = $this->small_repo->findOrFail($id);
$breadcrumb = array(
'Accueil' => route('modulus.dashboard'),
'Exemples' => route('module.small.index'),
'Modifier' => null
);
return view('small::app.small.form')->with([
'title' => '<i class="fa fa-magic mr-1"></i>Exemples',
'action' => '<i class="fa fa-plus mr-2"></i>Modification',
'breadcrumb' => $breadcrumb,
'item' => $small
]);
}
/**
* Store a newly created resource in storage.
* @param SmallStoreRequest $request
* @return Renderable
*/
public function store(SmallStoreRequest $request, $id = null)
{
return $this->update($request, $id);
}
/**
* Show the specified resource.
* @param int $id
* @return Renderable
*/
public function show(Request $request, $id)
{
$small = $this->small_repo->findOrFail($id);
$breadcrumb = array(
'Accueil' => route('modulus.dashboard'),
'Exemples' => route('module.small.index'),
'Voir' => null
);
return view('small::app.small.show')->with([
'title' => '<i class="fa fa-magic mr-1"></i>Exemples',
'subtitle' => $small->name,
'breadcrumb' => $breadcrumb,
'item' => $small
]);
}
/**
* Update the specified resource in storage.
* @param SmallStoreRequest $request
* @param int $id
* @return Renderable
*/
public function update(SmallStoreRequest $request, $id)
{
$small_data = collect($request->except(['_token']));
$small = $this->small_repo->store($small_data, $id);
Session::flash('success', "Exemple ". (is_null($id) ? 'créé' : 'modifié') . " avec succès");
return Redirect::route('module.small.index');
}
public function duplicate($id)
{
$this->checkPermissionAccess($id);
$this->small_repo->duplicate($id);
Session::flash('success', "Exemple dupliqué avec succès");
return Redirect::route('module.small.index');
}
/**
* Remove the specified resource from storage.
* @param int $id
* @return Renderable
*/
public function destroy($id)
{
$this->checkPermissionAccess($id);
$this->small_repo->destroy($id);
Session::flash('success', 'Exemple supprimé avec succès');
return Redirect::route('module.small.index');
}
/**
* Exporte les données de la exemple
*
* @param int $id
* @return void
*/
public function export()
{
return Excel::download(new SmallExport, date('Ymd_His_') . 'export-module-small.xlsx');
}
}
<?php
namespace Modules\Small\Http\Repositories;
use Illuminate\Support\Str;
use Illuminate\Support\Collection;
use Modules\Small\Models\Small;
use Goldenscarab\Modulus\App\Http\Repositories\RepositoryInterface;
class SmallRepository implements RepositoryInterface {
public function all($columns = array('*'))
{
return Small::select($columns)->orderBy('id', 'asc')->get();
}
public function list($sorting, $direction = 'asc', $perpage = 15, $search = "", $user_id = null)
{
// Si tri via relation
if (Str::contains($sorting, '.')) {
// Préparation de la jointure
$relation_filter = explode('.', $sorting);
$table_join = $relation_filter[0];
$primary_key = $table_join . '.id';
$foreign_key = Str::singular(collect(explode('_', $table_join))->last()) . '_id';
// Récupération des éléments
$list = Small::select('small.*')
->join($table_join, $primary_key, '=', $foreign_key)
->user($user_id)
->orderBy($sorting, $direction)
->search($search)->paginate($perpage);
} else {
$list = Small::search($search)->user($user_id)->orderBy($sorting, $direction)->paginate($perpage);
}
return $list;
}
public function published($columns = array('*'))
{
return Small::select($columns)->active()->orderBy('title', 'asc')->get();
}
public function new()
{
return new Small;
}
public function store(Collection $data, $id = null)
{
if (is_null($id)) {
$small = new Small;
} else {
$small = Small::findOrFail($id);
}
$small->name = $data->get('name');
$small->user_id = $data->get('user_id');
$small->save();
return $small;
}
public function find($id, $columns = array('*'))
{
return Small::select($columns)->find($id);
}
public function findOrFail($id, $columns = array('*'))
{
return Small::select($columns)->findOrFail($id);
}
public function findBy($field, $value, $columns = array('*'))
{
return Small::select($columns)->where($field, '=', $value)->first();
}
public function findOrFailBy($field, $value, $columns = array('*'))
{
return Small::select($columns)->where($field, '=', $value)->firstOrFail();
}
public function findAllBy($field, $value, $columns = array('*'))
{
return Small::select($columns)->where($field, '=', $value)->get();
}
public function findWhere($where, $columns = array('*'))
{
return Small::select($columns)->whereRaw($where)->get();
}
public function search($search)
{
return Small::search($search)->get();
}
public function destroy($id)
{
$item = Small::findOrFail($id);
return $item->delete();
}
public function first()
{
return Small::first();
}
public function lasts($limit)
{
return Small::latest()->limit($limit)->get();
}
public function duplicate($id)
{
$item = Small::findOrFail($id);
$clone = $item->replicate();
$availables = ['title', 'name', 'label', 'slug'];
foreach ($availables as $available) {
if (isset($clone->{$available})) {
$clone->{$available} = $clone->{$available} . ' (copie)';
}
}
$clone->start_at = null;
$clone->end_at = null;
$clone->save();
return $clone;
}
public function truncate()
{
return Small::truncate();
}
private function calcNextPosition()
{
$item = Small::orderBy('position', 'desc')->first();
if (is_null($item)) {
return 1;
}
return $item->position + 1;
}
}
<?php
namespace Modules\Small\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ConfigStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return auth()->user()->can('module-update');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'params1' => 'required|max:255'
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes()
{
return [
'params1' => 'Paramètre 1'
];
}
}
<?php
namespace Modules\Small\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SmallStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
if (empty($this->route('id'))) {
return auth()->user()->can('module-small-create');
} else {
return auth()->user()->can('module-small-update');
}
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:255',
'user_id' => 'required|exists:users,id'
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes()
{
return [
'name' => 'Nom',
'user_id' => 'Utilisateur',
];
}
}
<?php
namespace Modules\Small\Http\Services\Facades;
use Illuminate\Support\Facades\Facade;
class SmallService extends Facade
{
protected static function getFacadeAccessor()
{
return 'SmallService';
}
}
<?php
namespace Modules\Small\Http\Services;
use Modules\Small\Http\Repositories\SmallRepository;
class SmallService
{
private $small_repo;
public function __construct(SmallRepository $small)
{
$this->small_repo = $small;
}
public function all()
{
return $this->small_repo->all();
}
}
<?php
namespace Modules\Small\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class Config extends Model
{
protected $table = 'module_small_config';
protected $fillable = [];
protected $dates = [];
protected $searchable = [];
protected $casts = [];
protected $appends = [];
/* Relation */
/* Attributs */
/* Scopes */
/* Spécifique méthodes */
}
<?php
namespace Modules\Small\Models;
use Illuminate\Database\Eloquent\Model;
use Goldenscarab\Modulus\App\Models\User;
use Illuminate\Database\Eloquent\Builder;
class Small extends Model
{
protected $table = 'module_smalls';
protected $fillable = [];
protected $dates = [];
protected $searchable = ['name'];
protected $casts = [];
protected $appends = [];
/* Relation */
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
/* Attributs */
protected function getNameUpperAttribute()
{
return strtoupper($this->attributes['name']);
}
/* Scopes */
public function scopeSearch(Builder $request, $search)
{
if (is_null($search)) return $request;
// Pour rechercher tous les mots d'une phrase dans le champs
$search = str_replace(' ', '%', $search);
foreach ($this->searchable as $key => $column) {
if ($key == 0) {
$request->where($column, 'LIKE', '%' . $search . '%');
} else {
$request->orWhere($column, 'LIKE', '%' . $search . '%');
}
}
return $request;
}
public function scopeUser(Builder $query, $user_id)
{
if (is_null($user_id)) return $query;
return $query->where('user_id', $user_id);
}
/* Spécifique méthodes */
public function smallMethod()
{
return 'Small';
}
}
<?php
namespace Modules\Small\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* The module namespace to assume when generating URLs to actions.
*
* @var string
*/
protected $moduleNamespace = 'Modules\Small\Http\Controllers';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*
* @return void
*/
public function boot()
{
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('Small', '/Routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace)
->group(module_path('Small', '/Routes/api.php'));
}
}
<?php
namespace Modules\Small\Providers;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Factory;
class SmallServiceProvider extends ServiceProvider
{
/**
* @var string $moduleName
*/
protected $moduleName = 'Small';
/**
* @var string $moduleNameLower
*/
protected $moduleNameLower = 'small';
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->register(RouteServiceProvider::class);
// Déclaration des services
$this->app->bind('SmallService', \Modules\Small\Http\Services\SmallService::class);
// Déclaration des facades des services
$loader = AliasLoader::getInstance();
$loader->alias('SmallService', \Modules\Small\Http\Services\Facades\SmallService::class);
}
/**
* Register config.
*
* @return void
*/
protected function registerConfig()
{
$this->publishes([
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
], 'config');
$this->mergeConfigFrom(
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
);
}
/**
* Register views.
*
* @return void
*/
public function registerViews()
{
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'Resources/views');
$this->publishes([
$sourcePath => $viewPath
], ['views', $this->moduleNameLower . '-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
}
/**
* Register translations.
*
* @return void
*/
public function registerTranslations()
{
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (Config::get('view.paths') as $path) {
if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
$paths[] = $path . '/modules/' . $this->moduleNameLower;
}
}
return $paths;
}
}
// Pour la compatibilité avec Vue 2, exécuter la commande suivante
// npm i -D @vue/composition-api
Vue.component('loader', require('./components/Loader').default);
Vue.component('collector', require('./components/Collector').default);
This diff is collapsed.
This diff is collapsed.
@extends('modulus::layouts.app.adminlte')
@section('content')
<div class="card">
<div class="card-header">
<h3 class="card-title">Configuration</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-widget="collapse" data-toggle="tooltip" title="Collapse">
<i class="fa fa-minus"></i>
</button>
<button type="button" class="btn btn-tool" data-widget="remove" data-toggle="tooltip" title="Remove">
<i class="fa fa-times"></i>
</button>
</div>
</div>
<div class="card-body">
<form action="{{ route('module.small.config.post') }}" method="post">
@csrf
<div class="forw-row">
<div class="col">
{!! Field2::input([
'label' => 'Paramètre 1',
'name' => 'params1',
'value' => $config->params1
]) !!}
</div>
</div>
<div class="form-action">
<a href="{{ route('modulus.module.index') }}" class="btn btn-warning">
<i class="fa fa-reply" aria-hidden="true"></i>
</a>
<button class="btn btn-success" type="submit">
<i class="fa fa-floppy-o" aria-hidden="true"></i>
</button>
</div>
</form>
</div>
</div>
@endsection
@extends('modulus::layouts.app.form')
@section('fields')
<div class="card">
<div class="card-header">
@isset ($action)
<h3 class="card-title">{!! $action !!}</h3>
@endisset
</div>
<div class="card-body">
<div class="form-row">
<div class="col-sm-6">
{!! Field2::select([
'label' => 'Propriétaire',
'name' => 'user_id',
'value' => $item->user_id,
'prefix' => '<i class="fa fa-user"></i>',
'attributes' => [
'required' => true,
],
'options' => [
'source' => [
'call' => 'Goldenscarab\Modulus\App\Http\Controllers\Api\UserController@index',
'params' => ['perpage' => 999],
'target' => 'data'
],
'default' => ['value' => '', 'label' => 'Choisir...'],
'value' => ':id',
'label' => ['template' => [
'format' => '%s (%s)',
'args' => [':name', ':company']
]]
]
]) !!}
</div>
</div>
<div class="form-row">
<div class="col">
{!! Field2::input([
'label' => 'Nom',
'name' => 'name',
'value' => $item->name,
'prefix' => '<i class="fa fa-bookmark"></i>',
'attributes' => [
'placeholder' => 'ex : Le nom',
'required' => true,
]
]) !!}
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
});
</script>
@endpush
@extends('modulus::layouts.app.adminlte')
@php
$can_prefix = 'module-small';
$url_prefix = route('module.small.index');
$am = new \Goldenscarab\Modulus\Helpers\ActionMenu($can_prefix, $url_prefix);
$params_actions = [
[
'button' => $am->make('[CREATE]', ['attributes.class' => 'btn-sm btn-success']),
]
];
if (auth()->user()->hasRole('admin'))
$params_filter = [
[
'name' => 'user',
'prefix' => 'Filtre utilisateur',
'size' => 'sm',
'options' => [
'source' => [
'url' => route('api.users.index', ['perpage' => 999]),
'method' => 'GET',
'target' => 'data'
],
'placeholder' => ['value' => '', 'label' => '-- Tous les utilisateurs --'],
'value' => ':id',
'label' => ':name'
]
]
];
else {
$params_filter = [];
}
$params_header = [
'actions' => $params_actions,
'filters' => $params_filter,
'search' => true
];
$params_list = [
'source' => route('api.module.small.index'),
'menu' => [
'button' => $am->make('[READ]', ['attributes' => ['class' => 'btn-sm btn-success']]),
'dropdown' => [
'size' => 'sm',
'attributes' => ['class' => 'dropdown-menu-right'],
'items' => [
$am->make('[UPDATE]'),
$am->make('[DUPLICATE]'),
$am->make('[SEPARATOR]'),
$am->make('[DESTROY]')
]
]
],
'row' => [],
'columns' => array(
[
'label' => '#',
'value' => ':id',
'sortable' => 'id'
], [
'label' => 'Nom',
'value' => ':name',
'sortable' => 'name'
], [
'label' => 'Utilisateur',
'value' => ':user.name',
'sortable' => 'users.lastname',
'render' => 'badge(badge-success)',
], [
'label' => ['value' => 'Date', 'attributes' => ['class' => 'text-center']],
'value' => ':updated_at',
'sortable' => 'updated_at',
'render' => 'date_human_fr',
'attributes' => ['class' => 'text-center']
]
)
];
@endphp
@section('content')
<div id="app">
<glist
v-bind:header="{{ json_encode($params_header) }}"
v-bind:list="{{ json_encode($params_list) }}"
></glist>
</div>
@endsection
@extends('modulus::layouts.app.adminlte')
@section('content')
<div class="card">
<div class="card-body">
{{ $item->name }}
</div>
</div>
<div class="form-action">
<a href="{{ route('module.small.index') }}" class="btn btn-warning">
<i class="fa fa-reply" aria-hidden="true"></i>
</a>
</div>
@endsection
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group([
'middleware' => ['auth:api', 'auth.active', 'role:admin|client|visitor'],
'namespace' => 'Api',
'prefix' => 'backend/module/',
'as' => 'api.module.'
], function() {
Route::resource('small', SmallController::class);
});
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::group([
'middleware' => ['auth', 'auth.active', 'role:admin'],
'namespace' => 'App',
'prefix' => config('modulus.url_prefix') . 'module/',
'as' => 'module.'
], function() {
/* Configuration */
Route::group(['prefix' => 'small/config', 'as' => 'small.config.'], function() {
Route::get('/', 'ConfigController@index')->name('form');
Route::post('/', 'ConfigController@store')->name('post');
});
// Campagne
Route::group(['prefix' => 'small', 'as' => 'small.'], function() {
Route::get('/', 'SmallController@index')->name('index');
Route::get('create', 'SmallController@create')->name('create');
Route::get('read/{id}', 'SmallController@show')->name('show');
Route::get('edit/{id}', 'SmallController@edit')->name('edit');
Route::get('export/{id}', 'SmallController@export')->name('export');
Route::post('store/{id?}', 'SmallController@store')->name('store');
Route::get('destroy/{id}', 'SmallController@destroy')->name('destroy');
Route::get('duplicate/{id}', 'SmallController@duplicate')->name('duplicate');
});
});
{
"name": "nwidart/campaign",
"description": "",
"authors": [
{
"name": "Nicolas Widart",
"email": "n.widart@gmail.com"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\Campaign\\": ""
}
}
}
{
"name": "Small",
"alias": "small",
"version": "4.0",
"description": "Petit module exemple pour Modulus",
"icon": "<i class=\"fa fa-magic\"><\/i>",
"keywords": [],
"priority": 70,
"config": true,
"providers": [
"Modules\\Small\\Providers\\SmallServiceProvider"
],
"aliases": {},
"files": [],
"requires": []
}
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"cross-env": "^7.0",
"laravel-mix": "^5.0.1",
"laravel-mix-merge-manifest": "^0.1.2"
}
}
const dotenvExpand = require('dotenv-expand');
dotenvExpand(require('dotenv').config({ path: '../../.env'/*, debug: true*/}));
const mix = require('laravel-mix');
require('laravel-mix-merge-manifest');
mix.setPublicPath('../../public').mergeManifest();
mix.js(__dirname + '/Resources/assets/js/app.js', 'js/campaign.js')
.sass( __dirname + '/Resources/assets/sass/app.scss', 'css/campaign.css');
if (mix.inProduction()) {
mix.version();
}
#! /bin/bash
SOURCE_MODULE=$1
DUPLICATE_MODULE=$2
rm -rf $DUPLICATE_MODULE/
# Vérification des dépendances
if ! which rename >/dev/null; then
echo -e "\033[31mAttention : le paquet rename est nécesaire à l'exécution de ce script.\033[0m"
echo -e "« sudo apt install rename » pour installer le paquet"
exit 1
fi
# Duplication du dossier
cp -r $SOURCE_MODULE/ $DUPLICATE_MODULE/
# Renommage des fichiers
find $DUPLICATE_MODULE/ -name '*' | rename -v "s/${SOURCE_MODULE}/${DUPLICATE_MODULE}/g"
find $DUPLICATE_MODULE/ -name '*' | rename -v "s/${SOURCE_MODULE,,}/${DUPLICATE_MODULE,,}/g"
# Remplacement des termes
find $DUPLICATE_MODULE/ -type f -exec sed -i "s/${SOURCE_MODULE}/${DUPLICATE_MODULE}/g" {} +
find $DUPLICATE_MODULE/ -type f -exec sed -i "s/${SOURCE_MODULE,,}/${DUPLICATE_MODULE,,}/g" {} +
# Module visible
find $DUPLICATE_MODULE/ -type f -exec sed -i "s/\"hidden\": true/\"hidden\": false/g" {} +
echo -e "\033[32m✔ Duplication du module terminée\033[0m"
......@@ -33,6 +33,7 @@ class User extends Authenticatable
protected $hidden = [
'password',
'remember_token',
'api_token'
];
/**
......
......@@ -25,11 +25,13 @@ class ModulusServiceProvider extends ServiceProvider
return true;
}
$modulus_view = trim(config('url_prefix'), '/') . '*';
// Configuration de Carbon dans la langue locale
Carbon::setLocale(config('app.locale'));
date_default_timezone_set('Europe/Paris');
View::composer('*back*', function($view){
View::composer($modulus_view, function($view){
$view->with('modules_menu', ModuleService::getModulesConfig());
//$view->with('route_param', \Request::getQueryString());
});
......
......@@ -47,6 +47,11 @@ class PublishesServiceProvider extends ServiceProvider
__DIR__.'/../../public/images/' => public_path('images/'),
]);
// Modules
$this->publishes([
__DIR__.'/../../Modules/' => base_path('Modules/'),
]);
// Views
// $this->publishes([
// __DIR__.'/../views' => base_path('resources/views'),
......
......@@ -20,7 +20,9 @@ class RouteServiceProvider extends ServiceProvider
*/
public function boot()
{
define('AUTH_HOME', config('modulus.url_prefix'));
if (!defined('AUTH_HOME')) {
define('AUTH_HOME', config('modulus.url_prefix'));
}
$router = $this->app->router;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment