ldc-boutique-cnc-sable/app/Providers/RouteServiceProvider.php

225 lines
8 KiB
PHP
Raw Permalink Normal View History

2020-10-30 17:26:00 +01:00
<?php
2026-06-14 21:32:07 +02:00
declare(strict_types=1);
2020-10-30 17:26:00 +01:00
namespace App\Providers;
2026-06-14 21:32:07 +02:00
use App\Dto\ProductWithPricingDto;
feat: implement pagination using Pagination value object - Updated DataTableService to accept a Pagination object for pagination parameters. - Refactored paginateQuery method to utilize pageSize and pageNumber from Pagination. refactor: replace ActionExecutor with Executor in controller traits - Updated ChangesModelOrder, TogglesModelStar, and TogglesModelStatus traits to use Executor interface instead of ActionExecutor. feat: add PictureMetadata and Slug value objects - Introduced PictureMetadata for managing image metadata with validation. - Added Slug value object for slug generation and validation. feat: update breadcrumbs to support RangeDto - Modified breadcrumbs-bo.php to accept RangeDto in the edit route. test: add tests for RangesController - Added tests for accessing, creating, updating, and deleting ranges. - Included tests for toggling range status. test: add integration tests for range actions - Created tests for CreateRange, DeleteRange, and UpdateRange actions. - Validated input handling and database interactions. test: add unit tests for range input classes - Implemented tests for CreateRangeInput and UpdateRangeInput to validate input constraints. test: add unit tests for value objects - Added tests for PictureMetadata and Slug to ensure proper validation and instantiation. test: add unit tests for RangeDto - Created tests to verify RangeDto mapping from Range model. test: add unit tests for RangePolicy - Implemented tests for RangePolicy to validate permissions based on user roles.
2026-09-29 16:59:07 +02:00
use App\Lib\Helpers\RequestHelper;
2026-06-14 21:32:07 +02:00
use App\Models\Discount;
use App\Models\Faq;
use App\Models\Product;
2026-06-14 21:32:07 +02:00
use App\Models\ProductInco;
use App\Models\Range;
use App\Models\Slide;
use App\Models\Tag;
use Domain\Ports\Repositories\ProductRepository;
2020-10-30 17:26:00 +01:00
use Illuminate\Cache\RateLimiting\Limit;
2026-06-14 21:32:07 +02:00
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
2020-10-30 17:26:00 +01:00
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
2026-06-14 21:32:07 +02:00
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
2020-10-30 17:26:00 +01:00
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
use Shared\Pagination\Pagination;
2026-06-14 21:32:07 +02:00
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
2020-10-30 17:26:00 +01:00
class RouteServiceProvider extends ServiceProvider
{
2026-06-14 21:32:07 +02:00
public const string ROUTE_GROUP_WEB = 'web';
public const string ROUTE_GROUP_WEB_CREDENTIALS = 'credentials';
public const string ROUTE_GROUP_WEB_AJAX = 'web-ajax';
public const string ROUTE_GROUP_API = 'api';
private const int RATE_LIMIT_PER_MINUTE_FOR_CREDENTIALS = 6;
private const int RATE_LIMIT_PER_MINUTE_FOR_WEB = 60;
private const int RATE_LIMIT_PER_MINUTE_FOR_AJAX = 60;
private const int RATE_LIMIT_PER_MINUTE_FOR_API = 60;
2020-10-30 17:26:00 +01:00
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/';
2020-10-30 17:26:00 +01:00
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
2026-06-14 21:32:07 +02:00
#[\Override]
2020-10-30 17:26:00 +01:00
public function boot()
{
$this->configureRateLimiting();
feat: implement pagination using Pagination value object - Updated DataTableService to accept a Pagination object for pagination parameters. - Refactored paginateQuery method to utilize pageSize and pageNumber from Pagination. refactor: replace ActionExecutor with Executor in controller traits - Updated ChangesModelOrder, TogglesModelStar, and TogglesModelStatus traits to use Executor interface instead of ActionExecutor. feat: add PictureMetadata and Slug value objects - Introduced PictureMetadata for managing image metadata with validation. - Added Slug value object for slug generation and validation. feat: update breadcrumbs to support RangeDto - Modified breadcrumbs-bo.php to accept RangeDto in the edit route. test: add tests for RangesController - Added tests for accessing, creating, updating, and deleting ranges. - Included tests for toggling range status. test: add integration tests for range actions - Created tests for CreateRange, DeleteRange, and UpdateRange actions. - Validated input handling and database interactions. test: add unit tests for range input classes - Implemented tests for CreateRangeInput and UpdateRangeInput to validate input constraints. test: add unit tests for value objects - Added tests for PictureMetadata and Slug to ensure proper validation and instantiation. test: add unit tests for RangeDto - Created tests to verify RangeDto mapping from Range model. test: add unit tests for RangePolicy - Implemented tests for RangePolicy to validate permissions based on user roles.
2026-09-29 16:59:07 +02:00
Request::macro('pagination', function (int $defaultPageSize = 25): Pagination {
/** @var \Illuminate\Http\Request $this */
return RequestHelper::pagination($this, $defaultPageSize);
});
2026-06-14 21:32:07 +02:00
$this->routes(function (): void {
Route::middleware([
self::ROUTE_GROUP_WEB,
'admin-secure',
'throttle:' . self::ROUTE_GROUP_WEB,
])->name('bo.')->prefix('bo')
->group(base_path('routes/web-bo.php'));
2026-06-14 21:32:07 +02:00
Route::middleware([
self::ROUTE_GROUP_WEB,
'throttle:' . self::ROUTE_GROUP_WEB,
])->name('fo.')
->group(base_path('routes/web-fo.php'));
2026-06-14 21:32:07 +02:00
Route::middleware([
self::ROUTE_GROUP_WEB_AJAX,
'throttle:' . self::ROUTE_GROUP_WEB_AJAX,
])->name('ajax.')->prefix('ajax')
->group(base_path('routes/ajax-fo.php'));
Route::middleware([
self::ROUTE_GROUP_API,
'throttle:' . self::ROUTE_GROUP_API,
])->name('api.')->prefix('api')
->group(base_path('routes/api.php'));
2020-10-30 17:26:00 +01:00
});
2026-06-14 21:32:07 +02:00
Route::model('inco', ProductInco::class);
Route::model('faq', Faq::class);
2026-06-14 21:32:07 +02:00
Route::model('tag', Tag::class);
Route::model('slide', Slide::class);
Route::model('range', Range::class);
Route::model('discount', Discount::class);
Route::model('product', Product::class);
2026-06-14 21:32:07 +02:00
Route::bind(
'productWithPricingPublished',
fn (string $value) => $this->resolvePublishedProductWithPricing($value)
);
$this->cspReportRoute();
2020-10-30 17:26:00 +01:00
}
/**
* Configure the rate limiters for the application.
2026-06-14 21:32:07 +02:00
*/
protected function configureRateLimiting(): void
{
RateLimiter::for(
self::ROUTE_GROUP_WEB_CREDENTIALS,
fn (Request $request) => Limit::perMinute(self::RATE_LIMIT_PER_MINUTE_FOR_CREDENTIALS)
->by($request->user()?->id ?: resolve('clientIp'))
);
RateLimiter::for(
self::ROUTE_GROUP_WEB,
fn (Request $request) => Limit::perMinute(self::RATE_LIMIT_PER_MINUTE_FOR_WEB)
->by($request->user()?->id ?: resolve('clientIp'))
);
RateLimiter::for(
self::ROUTE_GROUP_WEB_AJAX,
fn (Request $request) => Limit::perMinute(self::RATE_LIMIT_PER_MINUTE_FOR_AJAX)
->by($request->user()?->id ?: resolve('clientIp'))
);
RateLimiter::for(
self::ROUTE_GROUP_API,
fn (Request $request) => Limit::perMinute(self::RATE_LIMIT_PER_MINUTE_FOR_API)
->by($request->user()?->id ?: resolve('clientIp'))
);
}
private function resolvePublishedProductWithPricing(string $value): ProductWithPricingDto
{
$domainProductRepository = resolve(ProductRepository::class);
$product = Product::query()
->where('slug', $value)
->published()
->firstOrFail();
if (Gate::denies('viewPublished', $product)) {
throw new NotFoundHttpException();
}
$product->load(['inco', 'validDiscount', 'products']);
$domainProduct = $domainProductRepository->find($product->getId());
$pricing = $domainProduct?->pricing();
2026-06-14 21:32:07 +02:00
if (! $pricing) {
throw new NotFoundHttpException();
}
return new ProductWithPricingDto($product, $pricing);
}
/**
* * Register CSP report URI
2020-10-30 17:26:00 +01:00
*
2026-06-14 21:32:07 +02:00
* Put this function inside RouteServiceProvider,
* and call it in RouteServiceProvider::boot
2020-10-30 17:26:00 +01:00
*/
2026-06-14 21:32:07 +02:00
private function cspReportRoute(): void
2020-10-30 17:26:00 +01:00
{
2026-06-14 21:32:07 +02:00
// * CSP REPORT URI, Please add /csp-report to VerifyCsrfToken $except middleware
Route::post('/csp-report', function (Request $request): void {
$isCspRequest = in_array(
request()->header('Content-Type'),
[
'application/reports+json',
'application/csp-report',
]
);
abort_if(! $isCspRequest, 401);
$cspReport = (function (array $data): array {
// Format Reporting API moderne
if (isset($data[0]['type']) && $data[0]['type'] === 'csp-violation') {
return (array) ($data[0]['body'] ?? []);
}
// Format CSP classique
if (isset($data['csp-report'])) {
return (array) $data['csp-report'];
}
return [];
})((array) $request->json()->all());
// * Filter array keys
$cspReport = Collection::make([
'document-uri' => Arr::string($cspReport, 'documentURL', Arr::string($cspReport, 'document-uri', 'unknown')),
'referrer' => Arr::string($cspReport, 'referrer', ''),
'blocked-uri' => Arr::string($cspReport, 'blockedURL', Arr::string($cspReport, 'blocked-uri', '')),
'effective-directive' => Arr::string($cspReport, 'effectiveDirective', Arr::string($cspReport, 'effective-directive', 'unknown')),
'original-policy' => Arr::string($cspReport, 'originalPolicy', Arr::string($cspReport, 'original-policy', 'unknown')),
'disposition' => Arr::string($cspReport, 'disposition', 'enforce'),
'status-code' => Arr::integer(
$cspReport,
'statusCode',
Arr::integer($cspReport, 'status-code', 200)
),
'line-number' => Arr::integer($cspReport, 'lineNumber'),
'column-number' => Arr::integer($cspReport, 'columnNumber'),
'source-file' => Arr::string($cspReport, 'sourceFile'),
]);
Log::warning(sprintf(
"CSP REPORT : \n %s",
$cspReport->transform(fn ($value, $key) => "\t{$key} -> {$value}")->join("\n")
));
})->middleware('throttle:5,2')
->withoutMiddleware(PreventRequestForgery::class)
->name('cspReportUri');
2020-10-30 17:26:00 +01:00
}
}