Compare commits
85 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
317577fb9b | ||
|
|
2a2490b302 | ||
|
|
53524b96d0 | ||
|
|
e7fe9d920b | ||
|
|
6e678b88c9 | ||
|
|
9c5cef6d99 | ||
|
|
0ab895e7ac | ||
|
|
06301a44fa | ||
|
|
4274b21eea | ||
|
|
dec444160b | ||
|
|
4dfa2d0412 | ||
|
|
a230697de0 | ||
|
|
2a9e109855 | ||
|
|
e19964fc89 | ||
|
|
edad0b4279 | ||
|
|
d70135b6af | ||
|
|
adae4da02f | ||
|
|
2f7289f531 | ||
|
|
6b85d63f5e | ||
|
|
5c5b34f33e | ||
|
|
ca47520a74 | ||
|
|
af3a63e36f | ||
|
|
21cc60457d | ||
|
|
36703bc9ac | ||
|
|
8a99cf98fc | ||
|
|
a4ed3dbb0f | ||
|
|
dae0c6271a | ||
|
|
98762d68a8 | ||
|
|
c450d71bed | ||
|
|
99f7545595 | ||
|
|
a0ddeda5a9 | ||
|
|
771978412a | ||
|
|
f43ea7c9ff | ||
|
|
c88583d727 | ||
|
|
6aab7d4eff | ||
|
|
0681bf8f0a | ||
|
|
923c3e0f6a | ||
|
|
8e48fc5ea1 | ||
|
|
615263f233 | ||
|
|
16f4af41fd | ||
|
|
d51f78a8db | ||
|
|
25b2e42f14 | ||
|
|
b9f51a1a5d | ||
|
|
e381de5e9c | ||
|
|
042e78583e | ||
|
|
e6796029ec | ||
|
|
39fc13dfe2 | ||
|
|
686bf307a2 | ||
|
|
549f874abd | ||
|
|
17ac0aaa5c | ||
|
|
f5367815e1 | ||
|
|
0d1f135616 | ||
|
|
817ffa68fc | ||
|
|
a31512216c | ||
|
|
cc24e547d2 | ||
|
|
16fe3773a9 | ||
|
|
8ce9d5734b | ||
|
|
6de828bc31 | ||
|
|
fe3eb7a955 | ||
|
|
c0bce88e75 | ||
|
|
61e900ee32 | ||
|
|
f44d9d7849 | ||
|
|
ecaec2823f | ||
|
|
22b598a11a | ||
|
|
d9c132ad25 | ||
|
|
634dbe832e | ||
|
|
f539cdd99a | ||
|
|
52dda4e346 | ||
|
|
8a3058e7bc | ||
|
|
97623ce240 | ||
|
|
7e8c4e7efd | ||
|
|
151e24d775 | ||
|
|
254a14a3f8 | ||
|
|
b600a890aa | ||
|
|
5d7c58f4cf | ||
|
|
91b8732434 | ||
|
|
0cc60c62d4 | ||
|
|
ae78c6d1fe | ||
|
|
95c9dd10d5 | ||
|
|
f7f14c6283 | ||
|
|
d454c83fec | ||
|
|
c9d988e64b | ||
|
|
00c809b8a0 | ||
|
|
c3831006e0 | ||
|
|
73412cd632 |
272 changed files with 37858 additions and 0 deletions
21
.editorconfig
Normal file
21
.editorconfig
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[docker-compose.yml]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.vue]
|
||||||
|
indent_size = 2
|
||||||
58
.env.example
Normal file
58
.env.example
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
APP_NAME=Laravel
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=laravel
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
BROADCAST_DRIVER=log
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=sync
|
||||||
|
SESSION_DRIVER=file
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=mailpit
|
||||||
|
MAIL_PORT=1025
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
PUSHER_APP_ID=
|
||||||
|
PUSHER_APP_KEY=
|
||||||
|
PUSHER_APP_SECRET=
|
||||||
|
PUSHER_HOST=
|
||||||
|
PUSHER_PORT=443
|
||||||
|
PUSHER_SCHEME=https
|
||||||
|
PUSHER_APP_CLUSTER=mt1
|
||||||
|
|
||||||
|
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
|
VITE_PUSHER_HOST="${PUSHER_HOST}"
|
||||||
|
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
||||||
|
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
|
||||||
|
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
55
.eslintrc.json
Normal file
55
.eslintrc.json
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:vue/vue3-strongly-recommended",
|
||||||
|
"@vue/eslint-config-typescript"
|
||||||
|
],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["*.ts", "*.vue"],
|
||||||
|
"rules": {
|
||||||
|
"no-undef": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.vue"],
|
||||||
|
"rules": {
|
||||||
|
"indent": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parser": "vue-eslint-parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["vue", "@typescript-eslint"],
|
||||||
|
"ignorePatterns": ["webpack.mix.js", "**/vendor/*.js", "**/vendor/**/*.js"],
|
||||||
|
"rules": {
|
||||||
|
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||||
|
"linebreak-style": ["error", "unix"],
|
||||||
|
"quotes": ["error", "double"],
|
||||||
|
"semi": ["error", "always"],
|
||||||
|
"vue/script-indent": ["error", 2, { "baseIndent": 0, "switchCase": 1 }],
|
||||||
|
"vue/one-component-per-file": "off"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"import/resolver": {
|
||||||
|
"node": {
|
||||||
|
"extensions": [".js", ".vue", ".ts", ".d.ts"]
|
||||||
|
},
|
||||||
|
"alias": {
|
||||||
|
"extensions": [".vue", ".js", ".ts", ".scss", ".d.ts"],
|
||||||
|
"map": [
|
||||||
|
["~", "./resources/assets"],
|
||||||
|
["@", "./node_modules"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.blade.php diff=html
|
||||||
|
*.css diff=css
|
||||||
|
*.html diff=html
|
||||||
|
*.md diff=markdown
|
||||||
|
*.php diff=php
|
||||||
|
|
||||||
|
/.github export-ignore
|
||||||
|
CHANGELOG.md export-ignore
|
||||||
|
.styleci.yml export-ignore
|
||||||
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/.phpunit.cache
|
||||||
|
/node_modules
|
||||||
|
/public/build
|
||||||
|
/public/hot
|
||||||
|
/public/storage
|
||||||
|
/storage/*.key
|
||||||
|
/vendor
|
||||||
|
.env
|
||||||
|
.env.backup
|
||||||
|
.env.production
|
||||||
|
Homestead.json
|
||||||
|
Homestead.yaml
|
||||||
|
auth.json
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
.phpunit.result.cache
|
||||||
|
/.fleet
|
||||||
|
/.idea
|
||||||
|
/.vscode
|
||||||
|
.stylelintcache
|
||||||
6
.gitlab/issue_templates/Bug.md
Normal file
6
.gitlab/issue_templates/Bug.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
## Comportement constaté
|
||||||
|
|
||||||
|
## Comportement attendu
|
||||||
|
|
||||||
|
## Solution envisagée## Étapes pour la reproduction du bug
|
||||||
|
* step
|
||||||
5
.gitlab/issue_templates/Feature.md
Normal file
5
.gitlab/issue_templates/Feature.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
## Présentation du besoin
|
||||||
|
|
||||||
|
## Implémentation
|
||||||
|
|
||||||
|
## Maquettes, documentations...
|
||||||
41
.stylelintrc.json
Normal file
41
.stylelintrc.json
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"stylelint-config-standard-scss",
|
||||||
|
"stylelint-config-sass-guidelines",
|
||||||
|
"stylelint-config-idiomatic-order"
|
||||||
|
],
|
||||||
|
"plugins": ["stylelint-scss"],
|
||||||
|
"files": ["**/*.css", "**/*.scss"],
|
||||||
|
"ignoreFiles": [
|
||||||
|
"**/vendor/*.css",
|
||||||
|
"**/vendor/**/*.css",
|
||||||
|
"**/vendor/*.scss",
|
||||||
|
"**/vendor/**/*.scss",
|
||||||
|
"**/vendor/*.sass",
|
||||||
|
"**/vendor/**/*.sass",
|
||||||
|
"**/vendor/*.less",
|
||||||
|
"**/vendor/**/*.less",
|
||||||
|
"**/vendor/*.vue",
|
||||||
|
"**/vendor/**/*.vue"
|
||||||
|
],
|
||||||
|
"customSyntax": "postcss-scss",
|
||||||
|
"rules": {
|
||||||
|
"indentation": 4,
|
||||||
|
"string-quotes": "double",
|
||||||
|
"selector-max-id": null,
|
||||||
|
"color-no-invalid-hex": true,
|
||||||
|
"order/properties-alphabetical-order": null,
|
||||||
|
"max-nesting-depth": 5,
|
||||||
|
"selector-max-compound-selectors": 5,
|
||||||
|
"scss/double-slash-comment-empty-line-before": [
|
||||||
|
"always",
|
||||||
|
{
|
||||||
|
"ignore": [
|
||||||
|
"between-comments",
|
||||||
|
"stylelint-commands",
|
||||||
|
"inside-block"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
22
.vscode/settings.json
vendored
Normal file
22
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"workbench.colorCustomizations": {
|
||||||
|
"activityBar.activeBackground": "#90431a",
|
||||||
|
"activityBar.background": "#90431a",
|
||||||
|
"activityBar.foreground": "#e7e7e7",
|
||||||
|
"activityBar.inactiveForeground": "#e7e7e799",
|
||||||
|
"activityBarBadge.background": "#1da24b",
|
||||||
|
"activityBarBadge.foreground": "#e7e7e7",
|
||||||
|
"commandCenter.border": "#e7e7e799",
|
||||||
|
"sash.hoverBorder": "#90431a",
|
||||||
|
"statusBar.background": "#652f12",
|
||||||
|
"statusBar.foreground": "#e7e7e7",
|
||||||
|
"statusBarItem.hoverBackground": "#90431a",
|
||||||
|
"statusBarItem.remoteBackground": "#652f12",
|
||||||
|
"statusBarItem.remoteForeground": "#e7e7e7",
|
||||||
|
"titleBar.activeBackground": "#652f12",
|
||||||
|
"titleBar.activeForeground": "#e7e7e7",
|
||||||
|
"titleBar.inactiveBackground": "#652f1299",
|
||||||
|
"titleBar.inactiveForeground": "#e7e7e799"
|
||||||
|
},
|
||||||
|
"peacock.remoteColor": "#652f12"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# StartCoQ
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
```
|
||||||
|
cp .env.example .env
|
||||||
|
php artisan key:generate
|
||||||
|
php artisan storage:link
|
||||||
|
php artisan migrate [--seed]
|
||||||
|
```
|
||||||
31
app/Console/Kernel.php
Normal file
31
app/Console/Kernel.php
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console;
|
||||||
|
|
||||||
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
|
class Kernel extends ConsoleKernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the application's command schedule.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function schedule(Schedule $schedule): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the commands for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function commands(): void
|
||||||
|
{
|
||||||
|
$this->load(__DIR__ . '/Commands');
|
||||||
|
|
||||||
|
require base_path('routes/console.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/Enums/Ingredients/FamilyEnum.php
Normal file
41
app/Enums/Ingredients/FamilyEnum.php
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Ingredients;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum FamilyEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case alcool = 1;
|
||||||
|
case flavor = 2;
|
||||||
|
case naturalCasings = 3;
|
||||||
|
case groceryStore = 4;
|
||||||
|
case spicesHerbs = 5;
|
||||||
|
case flourBreadcrumbs = 6;
|
||||||
|
case fruitsVegetables = 7;
|
||||||
|
case aromaticMixMarinade = 8;
|
||||||
|
case functionalMixSimpleIngredients = 9;
|
||||||
|
case meatProducts = 10;
|
||||||
|
case sauces = 11;
|
||||||
|
case dairyProducts = 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added families definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::alcool->name => 'Alcool',
|
||||||
|
self::flavor->name => 'Arôme',
|
||||||
|
self::naturalCasings->name => 'Boyaux Naturels',
|
||||||
|
self::groceryStore->name => 'Épicerie',
|
||||||
|
self::spicesHerbs->name => 'Épices et aromates',
|
||||||
|
self::flourBreadcrumbs->name => 'Farine / Chapelure',
|
||||||
|
self::fruitsVegetables->name => 'Fruits et légumes',
|
||||||
|
self::aromaticMixMarinade->name => 'Mix aromatique / Marinade',
|
||||||
|
self::functionalMixSimpleIngredients->name => 'Mix fonctionnel / ingredients simples',
|
||||||
|
self::meatProducts->name => 'Produits carnés',
|
||||||
|
self::sauces->name => 'Sauces',
|
||||||
|
self::dairyProducts->name => 'Produits laitiers',
|
||||||
|
];
|
||||||
|
}
|
||||||
43
app/Enums/Ingredients/FunctionEnum.php
Normal file
43
app/Enums/Ingredients/FunctionEnum.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Ingredients;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum FunctionEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case dye = 1;
|
||||||
|
case antiOxidant = 2;
|
||||||
|
case starch = 3;
|
||||||
|
case curator = 4;
|
||||||
|
case freezingAgent = 5;
|
||||||
|
case sweetener = 6;
|
||||||
|
case stabilizer = 7;
|
||||||
|
case emulsifier = 8;
|
||||||
|
case thickener = 9;
|
||||||
|
case sugar = 10;
|
||||||
|
case salt = 11;
|
||||||
|
case fiber = 12;
|
||||||
|
case protein = 13;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::dye->name => 'Colorant',
|
||||||
|
self::antiOxidant => 'Anti-oxidant',
|
||||||
|
self::starch->name => 'Amidon',
|
||||||
|
self::curator->name => 'Conservateur',
|
||||||
|
self::freezingAgent->name => 'Gelifiant',
|
||||||
|
self::sweetener->name => 'Edulcorant',
|
||||||
|
self::stabilizer->name => 'Stabilisateur',
|
||||||
|
self::emulsifier->name => 'Emulsifiant',
|
||||||
|
self::thickener->name => 'Epaississant',
|
||||||
|
self::sugar->name => 'Sucre',
|
||||||
|
self::salt->name => 'Sel',
|
||||||
|
self::fiber->name => 'Fibre',
|
||||||
|
self::protein->name => 'Protéine',
|
||||||
|
];
|
||||||
|
}
|
||||||
27
app/Enums/Ingredients/OriginEnum.php
Normal file
27
app/Enums/Ingredients/OriginEnum.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Ingredients;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum OriginEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case magazine = 1;
|
||||||
|
case photo = 2;
|
||||||
|
case web = 3;
|
||||||
|
case mail = 4;
|
||||||
|
case salon = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added origins->name definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::magazine->name => 'Magazine',
|
||||||
|
self::photo->name => 'Photo de rayon',
|
||||||
|
self::web->name => 'Web',
|
||||||
|
self::mail->name => 'Fournisseur/Mail',
|
||||||
|
self::salon->name => 'Salon'
|
||||||
|
];
|
||||||
|
}
|
||||||
25
app/Enums/Ingredients/PackagingEnum.php
Normal file
25
app/Enums/Ingredients/PackagingEnum.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Ingredients;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum PackagingEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case fees = 1;
|
||||||
|
case pasteurizedSterilized = 2;
|
||||||
|
case frozen = 3;
|
||||||
|
case bagDehydrated = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added packagings definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::fees->name => 'Frais',
|
||||||
|
self::pasteurizedSterilized->name => 'Pasteurisé / Stérilisé',
|
||||||
|
self::frozen->name => 'Surgelé',
|
||||||
|
self::bagDehydrated->name => 'Sac / déshydraté',
|
||||||
|
];
|
||||||
|
}
|
||||||
43
app/Enums/KeywordCategoryEnum.php
Normal file
43
app/Enums/KeywordCategoryEnum.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum KeywordCategoryEnum : string
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case ingredientPleasure = "ingredient_pleasure";
|
||||||
|
case ingredientPracticality = "ingredient_practicality";
|
||||||
|
case ingredientHealth = "ingredient_health";
|
||||||
|
case ingredienEthics = "ingredient_ethics";
|
||||||
|
case productPleasure = "product_pleasure";
|
||||||
|
case productShape = "product_shape";
|
||||||
|
case productPracticality = "product_practicality";
|
||||||
|
case productHealth = "product_health";
|
||||||
|
case productEthics = "product_ethics";
|
||||||
|
case packagingPleasure = "packaging_pleasure";
|
||||||
|
case packagingPracticality = "packaging_practicality";
|
||||||
|
case packagingEthics = "packaging_ethics";
|
||||||
|
case packagingDesign = "packaging_design";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::ingredientPleasure->name => 'IngredientPleasure',
|
||||||
|
self::ingredientPracticality->name => 'IngredientPracticality',
|
||||||
|
self::ingredientHealth->name => 'IngredientHealth',
|
||||||
|
self::ingredienEthics->name => 'IngredientEthics',
|
||||||
|
self::productPleasure->name => 'ProductPleasure',
|
||||||
|
self::productShape->name => 'ProductShape',
|
||||||
|
self::productPracticality->name => 'ProductPracticality',
|
||||||
|
self::productHealth->name => 'ProductHealth',
|
||||||
|
self::productEthics->name => 'ProductEthics',
|
||||||
|
self::packagingPleasure->name => 'PackagingPleasure',
|
||||||
|
self::packagingPracticality->name => 'PackagingPracticality',
|
||||||
|
self::packagingEthics->name => 'PackagingEthics',
|
||||||
|
self::packagingDesign->name => 'PackagingDesign',
|
||||||
|
];
|
||||||
|
}
|
||||||
37
app/Enums/Packaging/BenefitEnum.php
Normal file
37
app/Enums/Packaging/BenefitEnum.php
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Packaging;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum BenefitEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case resistance = 1;
|
||||||
|
case recyclability = 2;
|
||||||
|
case presentation = 3;
|
||||||
|
case openingClosing = 4;
|
||||||
|
case toaster = 5;
|
||||||
|
case traditionalOven = 6;
|
||||||
|
case microwaveOven = 7;
|
||||||
|
case communication = 8;
|
||||||
|
case barbecue = 9;
|
||||||
|
case others = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added benefits definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::resistance->name => 'Résistance',
|
||||||
|
self::recyclability->name => 'Recyclabilité',
|
||||||
|
self::presentation->name => 'Présentation',
|
||||||
|
self::openingClosing->name => 'Ouverture/Fermeture',
|
||||||
|
self::toaster->name => 'Grille pain',
|
||||||
|
self::traditionalOven->name => 'Four Traditionnel',
|
||||||
|
self::microwaveOven->name => 'Four micro-onde',
|
||||||
|
self::communication->name => 'Communication',
|
||||||
|
self::barbecue->name => 'Barbecue',
|
||||||
|
self::others->name => 'Autres'
|
||||||
|
];
|
||||||
|
}
|
||||||
35
app/Enums/Packaging/MaterialEnum.php
Normal file
35
app/Enums/Packaging/MaterialEnum.php
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Packaging;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum MaterialEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case plactic = 1;
|
||||||
|
case paper = 2;
|
||||||
|
case wood = 3;
|
||||||
|
case aluminium = 4;
|
||||||
|
case inox = 5;
|
||||||
|
case glass = 6;
|
||||||
|
case ceramic = 7;
|
||||||
|
case materials = 8;
|
||||||
|
case others = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added materials definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::plactic->name => 'Plastique',
|
||||||
|
self::paper->name => 'Carton/Papier',
|
||||||
|
self::wood->name => 'Bois/Osier',
|
||||||
|
self::aluminium->name => 'Aluminium',
|
||||||
|
self::inox->name => 'Acier/Inox',
|
||||||
|
self::glass->name => 'Verre',
|
||||||
|
self::ceramic->name => 'Céramique/Terre cuite/Grès',
|
||||||
|
self::materials->name => 'Multi Matériaux',
|
||||||
|
self::others->name => 'Autres'
|
||||||
|
];
|
||||||
|
}
|
||||||
27
app/Enums/Packaging/OriginEnum.php
Normal file
27
app/Enums/Packaging/OriginEnum.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Packaging;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum OriginEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case magazine = 1;
|
||||||
|
case photo = 2;
|
||||||
|
case web = 3;
|
||||||
|
case mail = 4;
|
||||||
|
case salon = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added origins definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::magazine->name => 'Magazine',
|
||||||
|
self::photo->name => 'Photo de rayon',
|
||||||
|
self::web->name => 'Web',
|
||||||
|
self::mail->name => 'Fournisseur/Mail',
|
||||||
|
self::salon->name => 'Salon'
|
||||||
|
];
|
||||||
|
}
|
||||||
37
app/Enums/Packaging/TypeEnum.php
Normal file
37
app/Enums/Packaging/TypeEnum.php
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Packaging;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum TypeEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case box = 1;
|
||||||
|
case bag = 2;
|
||||||
|
case jar = 3;
|
||||||
|
case bottle = 4;
|
||||||
|
case film = 5;
|
||||||
|
case sleeves = 6;
|
||||||
|
case blister = 7;
|
||||||
|
case sheathCase = 8;
|
||||||
|
case tag = 9;
|
||||||
|
case others = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added types definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::box->name => 'Boîte/Barquette/Bol',
|
||||||
|
self::bag->name => 'Sac/Sachet',
|
||||||
|
self::jar->name => 'Pot',
|
||||||
|
self::bottle->name => 'Bouteille/Gobelet/Flacon',
|
||||||
|
self::film->name => 'Film',
|
||||||
|
self::sleeves->name => 'Sleeves',
|
||||||
|
self::blister->name => 'Tube/Blister/Feuille',
|
||||||
|
self::sheathCase->name => 'Étui fourreau',
|
||||||
|
self::tag->name => 'Étiquettes',
|
||||||
|
self::others->name => 'Autres'
|
||||||
|
];
|
||||||
|
}
|
||||||
21
app/Enums/Packaging/WatchTypeEnum.php
Normal file
21
app/Enums/Packaging/WatchTypeEnum.php
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Packaging;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum WatchTypeEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case product = 1;
|
||||||
|
case packaging = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added watch types definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::product->name => 'Produit Fini',
|
||||||
|
self::packaging->name => 'Emballage',
|
||||||
|
];
|
||||||
|
}
|
||||||
16
app/Enums/Pagination/ItemsPerPaginationEnum.php
Normal file
16
app/Enums/Pagination/ItemsPerPaginationEnum.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Pagination;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum ItemsPerPaginationEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case five = 5;
|
||||||
|
case twelve = 12;
|
||||||
|
case twentyfive = 25;
|
||||||
|
case fifty = 50;
|
||||||
|
case onehundred = 100;
|
||||||
|
}
|
||||||
31
app/Enums/Process/BenefitEnum.php
Normal file
31
app/Enums/Process/BenefitEnum.php
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Process;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum BenefitEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case rateGain = 1;
|
||||||
|
case capacityGain = 2;
|
||||||
|
case efficiencyGain = 3;
|
||||||
|
case laborGain = 4;
|
||||||
|
case packagingGain = 5;
|
||||||
|
case energyGain = 6;
|
||||||
|
case others = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added benefits definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::rateGain->name => 'Gain Cadence',
|
||||||
|
self::capacityGain->name => 'Gain capacité',
|
||||||
|
self::efficiencyGain->name => 'Gain rendement',
|
||||||
|
self::laborGain->name => 'Gain main d\'oeuvre',
|
||||||
|
self::packagingGain->name => 'Conso Emballage',
|
||||||
|
self::energyGain->name => 'Conso Energie',
|
||||||
|
self::others->name => 'Autres'
|
||||||
|
];
|
||||||
|
}
|
||||||
31
app/Enums/Process/MeatPreparationEnum.php
Normal file
31
app/Enums/Process/MeatPreparationEnum.php
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Process;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum MeatPreparationEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case cutting = 1;
|
||||||
|
case mixture = 2;
|
||||||
|
case grinding = 3;
|
||||||
|
case nibbling = 4;
|
||||||
|
case churning = 5;
|
||||||
|
case injection = 6;
|
||||||
|
case others = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added meat preparations definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::cutting->name => 'Cutterage',
|
||||||
|
self::mixture->name => 'Mélange',
|
||||||
|
self::grinding->name => 'Broyage',
|
||||||
|
self::nibbling->name => 'Grignotage',
|
||||||
|
self::churning->name => 'Barattage',
|
||||||
|
self::injection->name => 'Injection',
|
||||||
|
self::others->name => 'Autres'
|
||||||
|
];
|
||||||
|
}
|
||||||
27
app/Enums/Process/OriginEnum.php
Normal file
27
app/Enums/Process/OriginEnum.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Process;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum OriginEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case magazine = 1;
|
||||||
|
case photo = 2;
|
||||||
|
case web = 3;
|
||||||
|
case mail = 4;
|
||||||
|
case salon = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added origins definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::magazine->name => 'Magazine',
|
||||||
|
self::photo->name => 'Photo de rayon',
|
||||||
|
self::web->name => 'Web',
|
||||||
|
self::mail->name => 'Fournisseur/Mail',
|
||||||
|
self::salon->name => 'Salon'
|
||||||
|
];
|
||||||
|
}
|
||||||
29
app/Enums/Process/PrimaryPackingEnum.php
Normal file
29
app/Enums/Process/PrimaryPackingEnum.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Process;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum PrimaryPackingEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case sealing = 1;
|
||||||
|
case thermoforming = 2;
|
||||||
|
case verticalBagging = 3;
|
||||||
|
case horizontalBagging = 4;
|
||||||
|
case skin = 5;
|
||||||
|
case others = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added primary packagings definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::sealing->name => 'Operculage',
|
||||||
|
self::thermoforming->name => 'Thermoformage',
|
||||||
|
self::verticalBagging->name => 'Ensachage Vertical',
|
||||||
|
self::horizontalBagging->name => 'Ensachage Horizontal',
|
||||||
|
self::skin->name => 'Skin',
|
||||||
|
self::others->name => 'Autres'
|
||||||
|
];
|
||||||
|
}
|
||||||
49
app/Enums/Process/TypeEnum.php
Normal file
49
app/Enums/Process/TypeEnum.php
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Process;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum TypeEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case slaughter = 1;
|
||||||
|
case beef = 2;
|
||||||
|
case slicing = 3;
|
||||||
|
case cook = 4;
|
||||||
|
case freezing = 5;
|
||||||
|
case forming = 6;
|
||||||
|
case mainPackaging = 7;
|
||||||
|
case secondPackaging = 8;
|
||||||
|
case calibring = 9;
|
||||||
|
case inspection = 10;
|
||||||
|
case identification = 11;
|
||||||
|
case labeling = 12;
|
||||||
|
case conveyance = 13;
|
||||||
|
case logistics = 14;
|
||||||
|
case robotization = 15;
|
||||||
|
case others = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added types definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::slaughter->name => 'Abbattage/Découpe',
|
||||||
|
self::beef->name => 'Préparation de viande',
|
||||||
|
self::slicing->name => 'Tranchage/Émincage',
|
||||||
|
self::cook->name => 'Cuisson',
|
||||||
|
self::freezing->name => 'Refroidissement/Surgélation',
|
||||||
|
self::forming->name => 'Formage/Embossage/Portionnage',
|
||||||
|
self::mainPackaging->name => 'Conditionnement primaire',
|
||||||
|
self::secondPackaging->name => 'Conditionnement secondaire',
|
||||||
|
self::calibring->name => 'Pesage/Calibrage',
|
||||||
|
self::inspection->name => 'Contrôles/Inspection',
|
||||||
|
self::identification->name => 'Identification (Marqueurs/Jets d\'encres',
|
||||||
|
self::labeling->name => 'Étiquetage',
|
||||||
|
self::conveyance->name => 'Convoyage/Transitique',
|
||||||
|
self::logistics->name => 'Logistiques',
|
||||||
|
self::robotization->name => 'Robotisation',
|
||||||
|
self::others->name => 'Autres'
|
||||||
|
];
|
||||||
|
}
|
||||||
23
app/Enums/Process/WatchTypeEnum.php
Normal file
23
app/Enums/Process/WatchTypeEnum.php
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Process;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum WatchTypeEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case product = 1;
|
||||||
|
case packaging = 2;
|
||||||
|
case process = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added watch types definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::product->name => 'Produit Fini',
|
||||||
|
self::packaging->name => 'Emballage',
|
||||||
|
self::process->name => 'Process',
|
||||||
|
];
|
||||||
|
}
|
||||||
29
app/Enums/Products/CertificationEnum.php
Normal file
29
app/Enums/Products/CertificationEnum.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum CertificationEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case bioAB = 1;
|
||||||
|
case labelRouge = 2;
|
||||||
|
case certifiedCQ = 3;
|
||||||
|
case standard = 4;
|
||||||
|
case freeRange = 6;
|
||||||
|
case others = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::bioAB->name => 'Bio AB ou Européen',
|
||||||
|
self::labelRouge->name => 'Label Rouge',
|
||||||
|
self::certifiedCQ->name => 'Certifié CQ',
|
||||||
|
self::standard->name => 'Standard',
|
||||||
|
self::freeRange->name => 'Free Range',
|
||||||
|
self::others->name => 'Autres',
|
||||||
|
];
|
||||||
|
}
|
||||||
40
app/Enums/Products/ClaimEnum.php
Normal file
40
app/Enums/Products/ClaimEnum.php
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum ClaimEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case productOfYear = 1;
|
||||||
|
case omega3 = 2;
|
||||||
|
case withoutOgm = 3;
|
||||||
|
case withoutGluten = 4;
|
||||||
|
case withoutAdditives = 5;
|
||||||
|
case withoutAntibiotics = 6;
|
||||||
|
case vegetarian = 7;
|
||||||
|
case lightweight = 8;
|
||||||
|
case halal = 9;
|
||||||
|
case highVitamins = 10;
|
||||||
|
case others = 99;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::productOfYear->name => 'Produit de l\'année',
|
||||||
|
self::omega3->name => 'Bleu Blanc Coeur, source d\'Omega 3',
|
||||||
|
self::withoutOgm->name => 'Sans OGM',
|
||||||
|
self::withoutGluten->name => 'Sans gluten',
|
||||||
|
self::withoutAdditives->name => 'Sans additif, sans colorant, sans conservateur,
|
||||||
|
100% simple, sans polyphosphate, sans sel nitrité',
|
||||||
|
self::withoutAntibiotics->name => 'Sans Antibiotique',
|
||||||
|
self::vegetarian->name => 'Vegan',
|
||||||
|
self::lightweight->name => 'Allégé',
|
||||||
|
self::halal->name => 'Halal, Casher',
|
||||||
|
self::highVitamins->name => 'Riche en protéines, fibres, calcium…',
|
||||||
|
self::others->name => 'Autres',
|
||||||
|
];
|
||||||
|
}
|
||||||
25
app/Enums/Products/DistributionNetworkEnum.php
Normal file
25
app/Enums/Products/DistributionNetworkEnum.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum DistributionNetworkEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case gms = 1;
|
||||||
|
case freezer = 2;
|
||||||
|
case restauration = 3;
|
||||||
|
case product = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::gms->name => 'GMS / Hard discount / Commerce de détail',
|
||||||
|
self::freezer->name => 'Home service/ Freezer Center',
|
||||||
|
self::restauration->name => 'Restauration',
|
||||||
|
self::product->name => 'Produit pour industrie agro-alimentaire',
|
||||||
|
];
|
||||||
|
}
|
||||||
29
app/Enums/Products/GeoAreaEnum.php
Normal file
29
app/Enums/Products/GeoAreaEnum.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum GeoAreaEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case french = 1;
|
||||||
|
case european = 2;
|
||||||
|
case asia = 3;
|
||||||
|
case america = 4;
|
||||||
|
case africa = 5;
|
||||||
|
case oceania = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::french->name => 'France',
|
||||||
|
self::european->name => 'Europe',
|
||||||
|
self::asia->name => 'Asie',
|
||||||
|
self::america->name => 'Amérique',
|
||||||
|
self::africa->name => 'Afrique',
|
||||||
|
self::oceania->name => 'Océanie',
|
||||||
|
];
|
||||||
|
}
|
||||||
31
app/Enums/Products/OriginEnum.php
Normal file
31
app/Enums/Products/OriginEnum.php
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum OriginEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case frenchPreparation = 1;
|
||||||
|
case frenchProduct = 2;
|
||||||
|
case igp = 3;
|
||||||
|
case regionalOrigins = 4;
|
||||||
|
case aoc = 5;
|
||||||
|
case ue = 6;
|
||||||
|
case others = 99;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::frenchPreparation->name => 'Né, élevé et préparé en France',
|
||||||
|
self::frenchProduct->name => 'Produit en France',
|
||||||
|
self::igp->name => 'IGP',
|
||||||
|
self::regionalOrigins->name => 'Origines régionales',
|
||||||
|
self::aoc->name => 'AOC',
|
||||||
|
self::ue->name => 'UE',
|
||||||
|
self::others->name => 'Autres',
|
||||||
|
];
|
||||||
|
}
|
||||||
43
app/Enums/Products/RangeEnum.php
Normal file
43
app/Enums/Products/RangeEnum.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum RangeEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case crus = 1;
|
||||||
|
case elaboratedRaw = 2;
|
||||||
|
case culinaryAids = 3;
|
||||||
|
case cooked = 4;
|
||||||
|
case smoked = 5;
|
||||||
|
case cookingSauce = 6;
|
||||||
|
case breaded = 7;
|
||||||
|
case rawMeat = 8;
|
||||||
|
case cookedMeats = 9;
|
||||||
|
case farcis = 10;
|
||||||
|
case plant = 12;
|
||||||
|
case frozenSpecific = 13;
|
||||||
|
case others = 11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::crus->name => 'Crus',
|
||||||
|
self::elaboratedRaw->name => 'Élaborés crus',
|
||||||
|
self::culinaryAids->name => 'Aides culinaires',
|
||||||
|
self::cooked->name => 'Cuits',
|
||||||
|
self::smoked->name => 'Fumés, confits ou séchés',
|
||||||
|
self::cookingSauce->name => 'Cuisine en sauce',
|
||||||
|
self::breaded->name => 'Panés',
|
||||||
|
self::rawMeat->name => 'Charcuterie crue',
|
||||||
|
self::cookedMeats->name => 'Charcuterie cuite',
|
||||||
|
self::farcis->name => 'Farcis',
|
||||||
|
self::plant->name => 'Végétal',
|
||||||
|
self::frozenSpecific->name => 'Spécifique surgelé',
|
||||||
|
self::others->name => 'Autres',
|
||||||
|
];
|
||||||
|
}
|
||||||
35
app/Enums/Products/RayEnum.php
Normal file
35
app/Enums/Products/RayEnum.php
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum RayEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case butchery = 1;
|
||||||
|
case poultry = 2;
|
||||||
|
case freshlyPackaged = 3;
|
||||||
|
case roastery = 4;
|
||||||
|
case caterer = 5;
|
||||||
|
case creamery = 7;
|
||||||
|
case groceryStore = 8;
|
||||||
|
case frozen = 9;
|
||||||
|
case others = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::butchery->name => 'Boucherie',
|
||||||
|
self::poultry->name => 'Volaille',
|
||||||
|
self::freshlyPackaged->name => 'Frais emballé',
|
||||||
|
self::roastery->name => 'Rôtisserie',
|
||||||
|
self::caterer->name => 'Traiteur',
|
||||||
|
self::creamery->name => 'Crémerie',
|
||||||
|
self::groceryStore->name => 'Épicerie',
|
||||||
|
self::frozen->name => 'Surgelé',
|
||||||
|
self::others->name => 'Autres',
|
||||||
|
];
|
||||||
|
}
|
||||||
38
app/Enums/Products/SourceEnum.php
Normal file
38
app/Enums/Products/SourceEnum.php
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Products;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum SourceEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
// * Catalogue argumentaire
|
||||||
|
case catalogArgumentary = 7;
|
||||||
|
// * Magasin
|
||||||
|
case magazin = 1;
|
||||||
|
// * Presse
|
||||||
|
case press = 3;
|
||||||
|
// * Salon Grand Public
|
||||||
|
case showConsumer = 6;
|
||||||
|
// * Salon Clients
|
||||||
|
case showCustomer = 5;
|
||||||
|
// * Salon Professionnel
|
||||||
|
case showTrade = 4;
|
||||||
|
// * Web
|
||||||
|
case web = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::catalogArgumentary->name => 'Catalogue Argumentaire',
|
||||||
|
self::magazin->name => 'Magasin',
|
||||||
|
self::press->name => 'Presse',
|
||||||
|
self::showConsumer->name => 'Salon Grand Public',
|
||||||
|
self::showCustomer->name => 'Salon Clients',
|
||||||
|
self::showTrade->name => 'Salon Professionnel',
|
||||||
|
self::web->name => 'Web',
|
||||||
|
];
|
||||||
|
}
|
||||||
23
app/Enums/Promotions/AngleEnum.php
Normal file
23
app/Enums/Promotions/AngleEnum.php
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Promotions;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum AngleEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case brand = 1;
|
||||||
|
case eco = 2;
|
||||||
|
case fun = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::brand->name => 'Démarche de la marque',
|
||||||
|
self::eco->name => 'Eco',
|
||||||
|
self::fun->name => 'Fun',
|
||||||
|
];
|
||||||
|
}
|
||||||
25
app/Enums/Promotions/DistributionNetworkEnum.php
Normal file
25
app/Enums/Promotions/DistributionNetworkEnum.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Promotions;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum DistributionNetworkEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case gms = 1;
|
||||||
|
case hd = 2;
|
||||||
|
case rhd = 3;
|
||||||
|
case export = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::gms->name => 'GMS',
|
||||||
|
self::hd->name => 'HD',
|
||||||
|
self::rhd->name => 'RHD',
|
||||||
|
self::export->name => 'Export',
|
||||||
|
];
|
||||||
|
}
|
||||||
29
app/Enums/Promotions/EventEnum.php
Normal file
29
app/Enums/Promotions/EventEnum.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Promotions;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum EventEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case birthday = 1;
|
||||||
|
case summer = 2;
|
||||||
|
case filmLicense = 3;
|
||||||
|
case christmas = 4;
|
||||||
|
case celebrityPartnership = 5;
|
||||||
|
case sport = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::birthday->name => 'Anniversaire',
|
||||||
|
self::summer->name => 'Été',
|
||||||
|
self::filmLicense->name => 'Licence film / Dessin animé',
|
||||||
|
self::christmas->name => 'Noël',
|
||||||
|
self::celebrityPartnership->name => 'Partenariat célébrité',
|
||||||
|
self::sport->name => 'Sport',
|
||||||
|
];
|
||||||
|
}
|
||||||
33
app/Enums/Promotions/LabelDistributionNetworkEnum.php
Normal file
33
app/Enums/Promotions/LabelDistributionNetworkEnum.php
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Promotions;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum LabelDistributionNetworkEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case allDistributions = 1;
|
||||||
|
case lidle = 2;
|
||||||
|
case aldi = 3;
|
||||||
|
case erteco = 4;
|
||||||
|
case netto = 5;
|
||||||
|
case leaderPrice = 6;
|
||||||
|
case noLvl2 = 7;
|
||||||
|
case others = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::allDistributions->name => 'Toutes les enseignes',
|
||||||
|
self::lidle->name => 'LIDL',
|
||||||
|
self::aldi->name => 'ALDI',
|
||||||
|
self::erteco->name => 'ERTECO',
|
||||||
|
self::netto->name => 'NETTO',
|
||||||
|
self::leaderPrice->name => 'LEADER PRICE',
|
||||||
|
self::noLvl2->name => 'Pas de niveau 2',
|
||||||
|
self::others->name => 'Autres',
|
||||||
|
];
|
||||||
|
}
|
||||||
27
app/Enums/Promotions/SourceEnum.php
Normal file
27
app/Enums/Promotions/SourceEnum.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Promotions;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum SourceEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case fieldTour = 1;
|
||||||
|
case headFeedback = 2;
|
||||||
|
case web = 3;
|
||||||
|
case press = 4;
|
||||||
|
case events = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::fieldTour->name => 'Tournée terrain',
|
||||||
|
self::headFeedback->name => 'Remontée chef Secteur',
|
||||||
|
self::web->name => 'Pige web',
|
||||||
|
self::press->name => 'Pige presse',
|
||||||
|
self::events->name => 'Salon / Évenementiel',
|
||||||
|
];
|
||||||
|
}
|
||||||
27
app/Enums/Promotions/TargetEnum.php
Normal file
27
app/Enums/Promotions/TargetEnum.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Promotions;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum TargetEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case women = 1;
|
||||||
|
case man = 2;
|
||||||
|
case junior = 3;
|
||||||
|
case senior = 4;
|
||||||
|
case allTargets = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::women->name => 'Femme',
|
||||||
|
self::man->name => 'Homme',
|
||||||
|
self::junior->name => 'Junior',
|
||||||
|
self::senior->name => 'Senior',
|
||||||
|
self::allTargets->name => 'Toutes cibles',
|
||||||
|
];
|
||||||
|
}
|
||||||
39
app/Enums/Promotions/TypeEnum.php
Normal file
39
app/Enums/Promotions/TypeEnum.php
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Promotions;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum TypeEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case animation = 1;
|
||||||
|
case reduction = 2;
|
||||||
|
case fidelity = 3;
|
||||||
|
case consoGames = 4;
|
||||||
|
case promotionalFormats = 5;
|
||||||
|
case flyer = 6;
|
||||||
|
case coBranding = 7;
|
||||||
|
case merchandising = 8;
|
||||||
|
case goodies = 9;
|
||||||
|
case promotionalMaterials = 10;
|
||||||
|
case ephemeralProducts = 11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::animation->name => 'Animation',
|
||||||
|
self::reduction->name => 'Réduction',
|
||||||
|
self::fidelity->name => 'Fidélité',
|
||||||
|
self::consoGames->name => 'Jeux Conso',
|
||||||
|
self::promotionalFormats->name => 'Formats promo',
|
||||||
|
self::flyer->name => 'OP Trade / Prospectus',
|
||||||
|
self::coBranding->name => 'Co-branding',
|
||||||
|
self::merchandising->name => 'PLV / Merchandising',
|
||||||
|
self::goodies->name => 'Primes / Goodies',
|
||||||
|
self::promotionalMaterials->name => 'Argumentaires Promo',
|
||||||
|
self::ephemeralProducts->name => 'Produits éphèmères',
|
||||||
|
];
|
||||||
|
}
|
||||||
43
app/Enums/Surveys/CustomerEnum.php
Normal file
43
app/Enums/Surveys/CustomerEnum.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Surveys;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum CustomerEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case francoscopie = 1;
|
||||||
|
case packaging = 2;
|
||||||
|
case innovation = 3;
|
||||||
|
case snacking = 4;
|
||||||
|
case vegetarian = 5;
|
||||||
|
case christmas = 6;
|
||||||
|
case barbecue = 7;
|
||||||
|
case sustainableDevelopment = 8;
|
||||||
|
case labelRouge = 9;
|
||||||
|
case bio = 10;
|
||||||
|
case certified = 11;
|
||||||
|
case bbc = 12;
|
||||||
|
case others = 13;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::francoscopie->name => 'Francoscopie',
|
||||||
|
self::packaging->name => 'Emaballages',
|
||||||
|
self::innovation->name => 'Innovation',
|
||||||
|
self::snacking->name => 'Snacking',
|
||||||
|
self::vegetarian->name => 'Vegan',
|
||||||
|
self::christmas->name => 'Noel',
|
||||||
|
self::barbecue->name => 'Barbecue',
|
||||||
|
self::sustainableDevelopment->name => 'Développement durable',
|
||||||
|
self::labelRouge->name => 'Label Rouge',
|
||||||
|
self::bio->name => 'BIO',
|
||||||
|
self::certified->name => 'Certifié',
|
||||||
|
self::bbc->name => 'BBC',
|
||||||
|
self::others->name => 'Autres',
|
||||||
|
];
|
||||||
|
}
|
||||||
25
app/Enums/Surveys/DistributionNetworkEnum.php
Normal file
25
app/Enums/Surveys/DistributionNetworkEnum.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Surveys;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum DistributionNetworkEnum : int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case gms = 1;
|
||||||
|
case freezer = 2;
|
||||||
|
case restauration = 3;
|
||||||
|
case product = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom added functions definition
|
||||||
|
*/
|
||||||
|
private const LABELS = [
|
||||||
|
self::gms->name => 'GMS / Hard discount / Commerce de détail',
|
||||||
|
self::freezer->name => 'Home service/ Freezer Center',
|
||||||
|
self::restauration->name => 'Restauration',
|
||||||
|
self::product->name => 'Produit pour industrie agro-alimentaire',
|
||||||
|
];
|
||||||
|
}
|
||||||
45
app/Exceptions/Handler.php
Normal file
45
app/Exceptions/Handler.php
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class Handler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A list of exception types with their corresponding custom log levels.
|
||||||
|
*
|
||||||
|
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
|
||||||
|
*/
|
||||||
|
protected $levels = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the exception types that are not reported.
|
||||||
|
*
|
||||||
|
* @var array<int, class-string<\Throwable>>
|
||||||
|
*/
|
||||||
|
protected $dontReport = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the inputs that are never flashed to the session on validation exceptions.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $dontFlash = [
|
||||||
|
'current_password',
|
||||||
|
'password',
|
||||||
|
'password_confirmation',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the exception handling callbacks for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->reportable(function (Throwable $e) {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/Http/Controllers/BrandController.php
Normal file
29
app/Http/Controllers/BrandController.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Brands\StoreBrandRequest;
|
||||||
|
use App\Models\Brand;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class BrandController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Brands\StoreBrandRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function store(StoreBrandRequest $request)
|
||||||
|
{
|
||||||
|
return DB::transaction(function () use ($request) {
|
||||||
|
$brand = new Brand();
|
||||||
|
$brand->fill($request->validated());
|
||||||
|
if ($brand->saveOrFail()) {
|
||||||
|
return \response()->json(['status' => true, 'brand' => $brand]);
|
||||||
|
}
|
||||||
|
return \response()->json(['status' => false, 'message' => __('La marque n\'a pas pu être créée')]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
152
app/Http/Controllers/Controller.php
Normal file
152
app/Http/Controllers/Controller.php
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
||||||
|
use App\Lib\Helpers\ToolboxHelper;
|
||||||
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class Controller extends BaseController
|
||||||
|
{
|
||||||
|
use AuthorizesRequests;
|
||||||
|
use DispatchesJobs;
|
||||||
|
use ValidatesRequests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Search query on specified fields
|
||||||
|
* splitting search into words or using whole sentence
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
|
||||||
|
* @param string $search The query string.
|
||||||
|
* @param callable $searchQuery The query string.
|
||||||
|
* @param string ...$fields Either a simple array or a string
|
||||||
|
* in case of a string the two fields
|
||||||
|
* would be concatenate to make the search.
|
||||||
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
|
*/
|
||||||
|
protected function searchQuery(
|
||||||
|
Builder $query,
|
||||||
|
string $search,
|
||||||
|
callable $searchQuery = null,
|
||||||
|
string ...$fields
|
||||||
|
): Builder {
|
||||||
|
if (count($fields)) {
|
||||||
|
// Search using words.
|
||||||
|
$words = explode(' ', $search);
|
||||||
|
$query->where(function ($query) use ($searchQuery, $words, $search, $fields) {
|
||||||
|
foreach ($words as $word) {
|
||||||
|
if (!strlen($word)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->searchOnFields($query, $word, $fields);
|
||||||
|
} //end foreach
|
||||||
|
// Search whole using whole sentence.
|
||||||
|
$this->searchOnFields($query, $search, $fields);
|
||||||
|
if ($searchQuery) {
|
||||||
|
$searchQuery($query);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} //end if
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build query search on all fields
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
* @param string $search
|
||||||
|
* @param array $fields
|
||||||
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
|
*/
|
||||||
|
private function searchOnFields(Builder $query, string $search, array $fields): Builder
|
||||||
|
{
|
||||||
|
$table = $query->getModel()->getTable();
|
||||||
|
foreach ($fields as $f) {
|
||||||
|
$f = str_replace('?', '\?', $f);
|
||||||
|
if (is_array($f)) {
|
||||||
|
$query->orWhereRaw(
|
||||||
|
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($f)->map(function ($q) use ($table) {
|
||||||
|
return "`$table`.`$q`";
|
||||||
|
})->implode(', \' \', ')),
|
||||||
|
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$query->orWhereRaw(
|
||||||
|
"UPPER(`$table`.`$f`) LIKE UPPER(?)",
|
||||||
|
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort columns with a query
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
* @param array $ignore
|
||||||
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
|
*/
|
||||||
|
protected function sortQuery(Builder $query, array $ignore = []): Builder
|
||||||
|
{
|
||||||
|
$rName = request()->route()->getName();
|
||||||
|
$table = $query->getModel()->getTable();
|
||||||
|
if (request()->sort_col) {
|
||||||
|
Session::put("$rName.sort_col", request()->sort_col);
|
||||||
|
Session::put("$rName.sorted", true);
|
||||||
|
}
|
||||||
|
if (request()->sort_way) {
|
||||||
|
Session::put("$rName.sort_way", request()->sort_way);
|
||||||
|
Session::put("$rName.sorted", true);
|
||||||
|
}
|
||||||
|
if (request()->rst) {
|
||||||
|
Session::remove("$rName.sorted");
|
||||||
|
Session::remove("$rName.sort_col");
|
||||||
|
Session::remove("$rName.sort_way");
|
||||||
|
}
|
||||||
|
if (request()->sort_col and request()->sort_way and Schema::hasColumn($table, request()->sort_col)) {
|
||||||
|
if (
|
||||||
|
!isset($ignore) or
|
||||||
|
(isset($ignore) and !in_array(request()->sort_col, $ignore))
|
||||||
|
) {
|
||||||
|
$query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->sort_way);
|
||||||
|
}
|
||||||
|
} elseif (Schema::hasColumn($table, 'order')) {
|
||||||
|
$query = $query->orderBy('order', 'ASC');
|
||||||
|
Session::put("$rName.sort_col", 'order');
|
||||||
|
Session::put("$rName.sort_way", 'asc');
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize pagination with cache or config (default).
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
* @param \App\Enums\Pagination\ItemsPerPaginationEnum|null $pagination
|
||||||
|
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||||
|
*/
|
||||||
|
protected function paginate(Builder $query, ItemsPerPaginationEnum $pagination = null): LengthAwarePaginator
|
||||||
|
{
|
||||||
|
$currentRoutePath = Str::slug(request()->route()->getName());
|
||||||
|
$cacheKey = "pagination.{$currentRoutePath}";
|
||||||
|
$pagination = $pagination ?? ItemsPerPaginationEnum::twelve->value;
|
||||||
|
$pagination = ToolboxHelper::getValidatedPaginate(
|
||||||
|
Cache::get($cacheKey, $pagination)
|
||||||
|
);
|
||||||
|
if (Cache::get($cacheKey) !== $pagination) {
|
||||||
|
Cache::put($cacheKey, $pagination);
|
||||||
|
}
|
||||||
|
$query = $query->paginate($pagination);
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/Http/Controllers/DashboardController.php
Normal file
18
app/Http/Controllers/DashboardController.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class DashboardController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Show products list.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
*/
|
||||||
|
public function show(): \Illuminate\Contracts\View\View
|
||||||
|
{
|
||||||
|
return view('pages.dashboard');
|
||||||
|
}
|
||||||
|
}
|
||||||
451
app/Http/Controllers/ProductController.php
Normal file
451
app/Http/Controllers/ProductController.php
Normal file
|
|
@ -0,0 +1,451 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Products\IndexFilterRequest;
|
||||||
|
use App\Http\Requests\Products\StoreProductRequest;
|
||||||
|
use App\Http\Requests\Products\UpdateProductRequest;
|
||||||
|
use App\Jobs\ExportProduct;
|
||||||
|
use App\Models\Brand;
|
||||||
|
use App\Models\Keyword;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Traits\Controllers\HasDocuments;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class ProductController extends Controller
|
||||||
|
{
|
||||||
|
use HasDocuments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Products\IndexFilterRequest $request
|
||||||
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
*/
|
||||||
|
public function index(IndexFilterRequest $request)
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\Database\Eloquent\Builder $brands */
|
||||||
|
$brandsQuery = Brand::query();
|
||||||
|
|
||||||
|
/** @var \Illuminate\Database\Eloquent\Builder $productsQuery */
|
||||||
|
$productsQuery = Product::query()->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
|
$this->requestFilters($request, $productsQuery);
|
||||||
|
|
||||||
|
$this->sortQuery($productsQuery);
|
||||||
|
|
||||||
|
$products = $this->paginate($productsQuery);
|
||||||
|
|
||||||
|
/** @var array $printMultiProduct Array of id */
|
||||||
|
$printMultiProduct = session('printMultiProduct') ?? [];
|
||||||
|
|
||||||
|
$brands = $brandsQuery->get();
|
||||||
|
|
||||||
|
$keywords = Keyword::query()->where('keyword_cat', 'LIKE', 'product_%')->get();
|
||||||
|
|
||||||
|
return view('pages.products.index', [
|
||||||
|
'products' => $products,
|
||||||
|
'brands' => $brands,
|
||||||
|
'keywords' => $keywords,
|
||||||
|
'printMultiProduct' => $printMultiProduct
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @param App\Models\Product $productModel
|
||||||
|
* @param Illuminate\Support\Collection $commentModel
|
||||||
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||||
|
*/
|
||||||
|
public function create(Product $productModel, Collection $commentModel): \Illuminate\Contracts\View\View
|
||||||
|
{
|
||||||
|
//phpcs:enable
|
||||||
|
$brands = Brand::all();
|
||||||
|
$productsFair = Product::query()->pluck('fair');
|
||||||
|
$productsShop = Product::query()->pluck('shop');
|
||||||
|
$productsCatalog = Product::query()->pluck('catalogue');
|
||||||
|
$keywords = Keyword::query()->where('keyword_cat', 'product_pleasure')
|
||||||
|
->orWhere('keyword_cat', 'product_shape')
|
||||||
|
->orWhere('keyword_cat', 'product_practicality')
|
||||||
|
->orWhere('keyword_cat', 'product_health')
|
||||||
|
->orWhere('keyword_cat', 'product_ethics')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('pages.products.create', compact(
|
||||||
|
'productModel',
|
||||||
|
'brands',
|
||||||
|
'productsFair',
|
||||||
|
'productsShop',
|
||||||
|
'productsCatalog',
|
||||||
|
'keywords',
|
||||||
|
'commentModel'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Products\StoreProductRequest $request
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function store(StoreProductRequest $request)
|
||||||
|
{
|
||||||
|
return DB::transaction(function () use ($request) {
|
||||||
|
$product = new Product();
|
||||||
|
$product->fill($request->validated());
|
||||||
|
$this->storeDocuments($request, $product);
|
||||||
|
if ($product->saveOrFail()) {
|
||||||
|
$this->updateCommentsModel($request, $product);
|
||||||
|
$product->productKeywords()->sync(collect($request->productKeywords)->pluck('id'));
|
||||||
|
return redirect()
|
||||||
|
->route('products.edit', $product)
|
||||||
|
->with('success', trans(
|
||||||
|
':model a été créé',
|
||||||
|
['model' => Str::singular(trans('models.classes.products'))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('error', trans(
|
||||||
|
':model n\'a pas été créé',
|
||||||
|
['model' => Str::singular(trans('models.classes.products'))]
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param \App\Models\Product $product
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function edit(Product $product)
|
||||||
|
{
|
||||||
|
$brands = Brand::all();
|
||||||
|
$productsFair = Product::query()->pluck('fair');
|
||||||
|
$productsShop = Product::query()->pluck('shop');
|
||||||
|
$productsCatalog = Product::query()->pluck('catalogue');
|
||||||
|
$commentModel = $product->productComments;
|
||||||
|
$keywords = Keyword::query()->where('keyword_cat', 'product_pleasure')
|
||||||
|
->orWhere('keyword_cat', 'product_shape')
|
||||||
|
->orWhere('keyword_cat', 'product_practicality')
|
||||||
|
->orWhere('keyword_cat', 'product_health')
|
||||||
|
->orWhere('keyword_cat', 'product_ethics')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('pages.products.edit', [
|
||||||
|
'productModel' => $product,
|
||||||
|
'brands' => $brands,
|
||||||
|
'productsFair' => $productsFair,
|
||||||
|
'productsShop' => $productsShop,
|
||||||
|
'productsCatalog' => $productsCatalog,
|
||||||
|
'commentModel' => $commentModel,
|
||||||
|
'keywords' => $keywords,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Products\UpdateProductRequest $request
|
||||||
|
* @param \App\Models\Product $product
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function update(UpdateProductRequest $request, Product $product)
|
||||||
|
{
|
||||||
|
return DB::transaction(function () use ($request, $product) {
|
||||||
|
$product->fill($request->validated());
|
||||||
|
$this->storeDocuments($request, $product);
|
||||||
|
$this->updateCommentsModel($request, $product);
|
||||||
|
$product->productKeywords()->sync(collect($request->productKeywords)->pluck('id'));
|
||||||
|
if ($product->saveOrFail()) {
|
||||||
|
return redirect()
|
||||||
|
->route('products.edit', $product)
|
||||||
|
->with('success', trans(
|
||||||
|
':model a été mis à jour',
|
||||||
|
['model' => Str::singular(trans('models.classes.products'))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('error', trans(
|
||||||
|
':model n\'a pas été mis à jour',
|
||||||
|
['model' => Str::singular(trans('models.classes.products'))]
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param \App\Models\Product $product
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function destroy(Product $product)
|
||||||
|
{
|
||||||
|
$this->deleteCommentsModel($product);
|
||||||
|
if ($product->deleteOrFail()) {
|
||||||
|
return redirect()
|
||||||
|
->route('products.index')
|
||||||
|
->with('warning', trans(
|
||||||
|
':model a bien été supprimé',
|
||||||
|
['model' => Str::singular(trans('models.classes.products'))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('error', trans(
|
||||||
|
':model n\'a pas été supprimé',
|
||||||
|
['model' => Str::singular(trans('models.classes.products'))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update comments model.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \App\Models\Product $product
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function updateCommentsModel(Request $request, Product $product)
|
||||||
|
{
|
||||||
|
$this->deleteCommentsModel($product);
|
||||||
|
if ($request->evaluation) {
|
||||||
|
foreach ($request->evaluation as $key => $value) {
|
||||||
|
$product->productComments()->create([
|
||||||
|
'evaluation' => $request->evaluation[$key],
|
||||||
|
'aspect' => $request->aspect[$key] ?? null,
|
||||||
|
'taste' => $request->taste[$key] ?? null,
|
||||||
|
'odor' => $request->odor[$key] ?? null,
|
||||||
|
'texture' => $request->texture[$key] ?? null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete comments model.
|
||||||
|
*
|
||||||
|
* @param \App\Models\Product $product
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function deleteCommentsModel(Product $product)
|
||||||
|
{
|
||||||
|
foreach ($product->productComments as $comment) {
|
||||||
|
if (!$comment->deleteOrFail()) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('error', trans(
|
||||||
|
':model n\'a pas été supprimé',
|
||||||
|
['model' => Str::singular(trans('models.classes.products'))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param \App\Models\Product $product
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function duplicate(Product $product)
|
||||||
|
{
|
||||||
|
$duplicatedProduct = $product->replicate();
|
||||||
|
foreach ($product->productComments as $comment) {
|
||||||
|
$duplicatedComments[] = $comment->replicate();
|
||||||
|
}
|
||||||
|
return $this->create($duplicatedProduct, collect($duplicatedComments ?? null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a boolean if the gencode is already used or not.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function checkGencode(Request $request)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
isset($request->GENCOD) &&
|
||||||
|
$request->GENCOD !== null &&
|
||||||
|
ctype_digit($request->GENCOD) &&
|
||||||
|
strlen($request->GENCOD) > 0
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
isset($request->ID) &&
|
||||||
|
$request->ID !== null &&
|
||||||
|
intval($request->GENCOD) === Product::where('id', $request->ID)->firstOrFail()->gencod
|
||||||
|
) {
|
||||||
|
$result = null;
|
||||||
|
} else {
|
||||||
|
$result = in_array(intval($request->GENCOD), Product::pluck('gencod')->toArray()) ?
|
||||||
|
Product::orderBy('created_at', 'desc')->where('gencod', intval($request->GENCOD))->first() : null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print product commercial sheet.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param integer $id
|
||||||
|
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||||
|
*/
|
||||||
|
public function printProductSheet(Request $request = null, int $id = null)
|
||||||
|
{
|
||||||
|
$productId = $id ?? intval($request->id);
|
||||||
|
$product = Product::where('id', $productId)->firstOrFail();
|
||||||
|
$title = trans('Fiche produit : :name - :appname', [
|
||||||
|
'name' => $product->name,
|
||||||
|
'appname' => \config('app.name', 'Startcoq')
|
||||||
|
]);
|
||||||
|
$filename = trans('fiche-product-:slug-:date', [
|
||||||
|
'slug' => Str::slug($product->name),
|
||||||
|
'date' => \now()->format('Y-m-d')
|
||||||
|
]);
|
||||||
|
return Product::generateProductPdf($product, $title)->stream("{$filename}.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print multi product commercial sheet
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||||
|
*/
|
||||||
|
public function printMultiProductSheet()
|
||||||
|
{
|
||||||
|
// FIXME: This should not use session.
|
||||||
|
/** @var array printMultiProduct */
|
||||||
|
$printMultiProduct = session('printMultiProduct') ?? [];
|
||||||
|
asort($printMultiProduct);
|
||||||
|
if (count($printMultiProduct)) {
|
||||||
|
$title = trans('Fiches produits - :appname', [
|
||||||
|
'appname' => \config('app.name', 'Startcoq')
|
||||||
|
]);
|
||||||
|
Product::generateMultipleProductPdf($printMultiProduct, $title)->stream();
|
||||||
|
} else {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('warning', trans('Veuillez sélectionner des produits'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print product commercial sheet
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||||
|
*/
|
||||||
|
public function printMultiProductUpdate(Request $request)
|
||||||
|
{
|
||||||
|
/** @var integer Id of the actual product */
|
||||||
|
$productId = intval($request->ID);
|
||||||
|
/** @var array Array of id products */
|
||||||
|
$printMultiProduct = session('printMultiProduct') ?? [];
|
||||||
|
|
||||||
|
if (in_array($productId, $printMultiProduct)) {
|
||||||
|
array_splice($printMultiProduct, array_search($productId, $printMultiProduct), 1);
|
||||||
|
$result = false;
|
||||||
|
} else {
|
||||||
|
$printMultiProduct[] = $productId;
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
session(['printMultiProduct' => $printMultiProduct]);
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the selection,
|
||||||
|
* destroy the specified session.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function printMultiProductDestroy()
|
||||||
|
{
|
||||||
|
session()->forget('printMultiProduct');
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('success', trans('Sélection des :model supprimée', ['model' => trans('models.classes.products')]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download a .zip file.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function download(Request $request)
|
||||||
|
{
|
||||||
|
\dispatch(new ExportProduct($request->id))->onConnection('database');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies filters from products.index
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Products\IndexFilterRequest $request
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $productsQuery
|
||||||
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
* @phpcs:disable Generic.Metrics.NestingLevel.TooHigh
|
||||||
|
*/
|
||||||
|
private function requestFilters(
|
||||||
|
IndexFilterRequest $request,
|
||||||
|
Builder $productsQuery
|
||||||
|
): \Illuminate\Database\Eloquent\Builder {
|
||||||
|
//phpcs:enable
|
||||||
|
foreach ($request->validated() as $parameterName => $queryParameter) {
|
||||||
|
$productsQuery->when(
|
||||||
|
!empty($queryParameter),
|
||||||
|
function (Builder $q) use ($queryParameter, $parameterName) {
|
||||||
|
switch ($parameterName) {
|
||||||
|
// * String type parameters (Approx search)
|
||||||
|
case 'name':
|
||||||
|
case 'shop':
|
||||||
|
case 'fair':
|
||||||
|
case 'catalogue':
|
||||||
|
case 'specified_claim':
|
||||||
|
$q->where($parameterName, 'LIKE', "%{$queryParameter}%");
|
||||||
|
break;
|
||||||
|
// * Number type parameters (Approx search)
|
||||||
|
case 'gencode':
|
||||||
|
$q->where($parameterName, \intval($queryParameter));
|
||||||
|
break;
|
||||||
|
// * Date type parameters
|
||||||
|
case 'date_before':
|
||||||
|
$q->whereDate('created_at', '<=', $queryParameter);
|
||||||
|
break;
|
||||||
|
case 'date_after':
|
||||||
|
$q->whereDate('created_at', '>=', $queryParameter);
|
||||||
|
break;
|
||||||
|
// * Enums Array
|
||||||
|
case 'claims':
|
||||||
|
case 'origins':
|
||||||
|
$q->whereJsonContains($parameterName, \collect($queryParameter)
|
||||||
|
->map(fn ($enumValue) => \intval($enumValue)));
|
||||||
|
break;
|
||||||
|
// * RelationShips parameters
|
||||||
|
case 'keywords':
|
||||||
|
$q->whereHas('productKeywords', function (Builder $subQ) use ($queryParameter) {
|
||||||
|
$subQ->whereIn('keywords.id', $queryParameter);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$q->where($parameterName, $queryParameter);
|
||||||
|
} //end switch
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} //end foreach
|
||||||
|
return $productsQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
62
app/Http/Kernel.php
Normal file
62
app/Http/Kernel.php
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
|
|
||||||
|
class Kernel extends HttpKernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The application's global HTTP middleware stack.
|
||||||
|
*
|
||||||
|
* These middleware are run during every request to your application.
|
||||||
|
*
|
||||||
|
* @var array<int, class-string|string>
|
||||||
|
*/
|
||||||
|
protected $middleware = [
|
||||||
|
\App\Http\Middleware\TrustHosts::class,
|
||||||
|
\App\Http\Middleware\TrustProxies::class,
|
||||||
|
\Illuminate\Http\Middleware\HandleCors::class,
|
||||||
|
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||||
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
|
\App\Http\Middleware\TrimStrings::class,
|
||||||
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's route middleware groups.
|
||||||
|
*
|
||||||
|
* @var array<string, array<int, class-string|string>>
|
||||||
|
*/
|
||||||
|
protected $middlewareGroups = [
|
||||||
|
'web' => [
|
||||||
|
\App\Http\Middleware\EncryptCookies::class,
|
||||||
|
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||||
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\App\Http\Middleware\SecureHeaders::class
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's middleware aliases.
|
||||||
|
*
|
||||||
|
* Aliases may be used to conveniently assign middleware to routes and groups.
|
||||||
|
*
|
||||||
|
* @var array<string, class-string|string>
|
||||||
|
*/
|
||||||
|
protected $middlewareAliases = [
|
||||||
|
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||||
|
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||||
|
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
|
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||||
|
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||||
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
20
app/Http/Middleware/Authenticate.php
Normal file
20
app/Http/Middleware/Authenticate.php
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class Authenticate extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the path the user should be redirected to when they are not authenticated.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
protected function redirectTo(Request $request): ?string
|
||||||
|
{
|
||||||
|
return $request->expectsJson() ? null : route('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
16
app/Http/Middleware/EncryptCookies.php
Normal file
16
app/Http/Middleware/EncryptCookies.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||||
|
|
||||||
|
class EncryptCookies extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The names of the cookies that should not be encrypted.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
];
|
||||||
|
}
|
||||||
16
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
16
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
|
||||||
|
|
||||||
|
class PreventRequestsDuringMaintenance extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The URIs that should be reachable while maintenance mode is enabled.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
];
|
||||||
|
}
|
||||||
34
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
34
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class RedirectIfAuthenticated
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure(\Illuminate\Http\Request):(\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
* @param string ...$guards
|
||||||
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
|
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, \Closure $next, string ...$guards): Response
|
||||||
|
{
|
||||||
|
// phpcs:enable
|
||||||
|
$guards = empty($guards) ? [null] : $guards;
|
||||||
|
|
||||||
|
foreach ($guards as $guard) {
|
||||||
|
if (Auth::guard($guard)->check()) {
|
||||||
|
return redirect(RouteServiceProvider::HOME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
105
app/Http/Middleware/SecureHeaders.php
Normal file
105
app/Http/Middleware/SecureHeaders.php
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\Facades\View;
|
||||||
|
use Illuminate\Support\Facades\Vite;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class SecureHeaders
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Enumerate headers which you do not want in your application's responses.
|
||||||
|
* Great starting point would be to go check out @Scott_Helme's:
|
||||||
|
* https://securityheaders.com/
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $unwantedHeaderList = [
|
||||||
|
'X-Powered-By',
|
||||||
|
'Server',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
|
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
// phpcs:enable
|
||||||
|
View::share('nonce', $nonce = Vite::useCspNonce());
|
||||||
|
// * For VueJS dev tool to execute
|
||||||
|
$jsDev = config('app.debug') ? "'unsafe-eval' 'unsafe-inline'" : "'nonce-{$nonce}' 'strict-dynamic'";
|
||||||
|
$scheme = config('app.env') === 'local' ? 'http' : 'https';
|
||||||
|
$reportUri = Route::has('cspReportUri') ?
|
||||||
|
\sprintf(' report-uri %s ;', \parse_url(route('cspReportUri'), \PHP_URL_PATH)) : '';
|
||||||
|
$this->removeUnwantedHeaders($this->unwantedHeaderList);
|
||||||
|
$response = $next($request);
|
||||||
|
$response->headers->set('Referrer-Policy', 'no-referrer-when-downgrade');
|
||||||
|
$response->headers->set('X-Content-Type-Options', 'nosniff');
|
||||||
|
$response->headers->set('X-XSS-Protection', '1; mode=block');
|
||||||
|
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
|
||||||
|
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains;');
|
||||||
|
$cspPolicies = [
|
||||||
|
"default-src 'none';",
|
||||||
|
"manifest-src 'self';",
|
||||||
|
// * CKEDITOR Specific https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/csp.html
|
||||||
|
"connect-src 'self' blob:;",
|
||||||
|
"img-src * data: blob:;",
|
||||||
|
'frame-src ' . implode(' ', [
|
||||||
|
'https://www.google.com/recaptcha/',
|
||||||
|
'https://recaptcha.google.com/recaptcha/',
|
||||||
|
'https://www.google.com/maps/',
|
||||||
|
'blob:'
|
||||||
|
]) . ';',
|
||||||
|
"object-src 'self' data:;",
|
||||||
|
"font-src 'self' data: https://fonts.gstatic.com;",
|
||||||
|
// ! Using CKEditor will must have unsafe-inline style
|
||||||
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||||
|
"style-src 'self' 'unsafe-inline' " . \implode(' ', [
|
||||||
|
'https://cdnjs.cloudflare.com',
|
||||||
|
// * File Manager
|
||||||
|
'https://fonts.googleapis.com',
|
||||||
|
'https://cdn.jsdelivr.net',
|
||||||
|
'https://use.fontawesome.com',
|
||||||
|
'https://fonts.googleapis.com'
|
||||||
|
]) . ';',
|
||||||
|
// ! If you dont use ckeditor use this
|
||||||
|
// "style-src 'self' 'nonce-$nonce';",
|
||||||
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||||
|
"script-src 'self' {$jsDev} " . \implode(' ', [
|
||||||
|
'https: blob:',
|
||||||
|
'https://www.googletagmanager.com',
|
||||||
|
'https://cdnjs.cloudflare.com',
|
||||||
|
"$scheme://www.google-analytics.com",
|
||||||
|
]) . ';'
|
||||||
|
];
|
||||||
|
|
||||||
|
$response->headers->set(
|
||||||
|
'Content-Security-Policy',
|
||||||
|
implode(' ', $cspPolicies) . $reportUri
|
||||||
|
);
|
||||||
|
$response->headers->set('Feature-Policy', 'fullscreen \'self\';');
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove unwanted headers
|
||||||
|
*
|
||||||
|
* @param array $headerList
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function removeUnwantedHeaders(array $headerList)
|
||||||
|
{
|
||||||
|
foreach ($headerList as $header) {
|
||||||
|
header_remove($header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Http/Middleware/TrimStrings.php
Normal file
19
app/Http/Middleware/TrimStrings.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
||||||
|
|
||||||
|
class TrimStrings extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The names of the attributes that should not be trimmed.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
'current_password',
|
||||||
|
'password',
|
||||||
|
'password_confirmation',
|
||||||
|
];
|
||||||
|
}
|
||||||
20
app/Http/Middleware/TrustHosts.php
Normal file
20
app/Http/Middleware/TrustHosts.php
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Http\Middleware\TrustHosts as Middleware;
|
||||||
|
|
||||||
|
class TrustHosts extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the host patterns that should be trusted.
|
||||||
|
*
|
||||||
|
* @return array<int, string|null>
|
||||||
|
*/
|
||||||
|
public function hosts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->allSubdomainsOfApplicationUrl(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Middleware/TrustProxies.php
Normal file
28
app/Http/Middleware/TrustProxies.php
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class TrustProxies extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The trusted proxies for this application.
|
||||||
|
*
|
||||||
|
* @var array<int, string>|string|null
|
||||||
|
*/
|
||||||
|
protected $proxies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers that should be used to detect proxies.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $headers =
|
||||||
|
Request::HEADER_X_FORWARDED_FOR |
|
||||||
|
Request::HEADER_X_FORWARDED_HOST |
|
||||||
|
Request::HEADER_X_FORWARDED_PORT |
|
||||||
|
Request::HEADER_X_FORWARDED_PROTO |
|
||||||
|
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||||
|
}
|
||||||
22
app/Http/Middleware/ValidateSignature.php
Normal file
22
app/Http/Middleware/ValidateSignature.php
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Routing\Middleware\ValidateSignature as Middleware;
|
||||||
|
|
||||||
|
class ValidateSignature extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The names of the query string parameters that should be ignored.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*
|
||||||
|
* 'fbclid',
|
||||||
|
* 'utm_campaign',
|
||||||
|
* 'utm_content',
|
||||||
|
* 'utm_medium',
|
||||||
|
* 'utm_source',
|
||||||
|
* 'utm_term',
|
||||||
|
*/
|
||||||
|
protected $except = [];
|
||||||
|
}
|
||||||
16
app/Http/Middleware/VerifyCsrfToken.php
Normal file
16
app/Http/Middleware/VerifyCsrfToken.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||||
|
|
||||||
|
class VerifyCsrfToken extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The URIs that should be excluded from CSRF verification.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
];
|
||||||
|
}
|
||||||
42
app/Http/Requests/Brands/StoreBrandRequest.php
Normal file
42
app/Http/Requests/Brands/StoreBrandRequest.php
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Brands;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreBrandRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|min:3|max:255',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get custom attributes for validator errors.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function attributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => trans('nom de la marque'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
60
app/Http/Requests/Products/IndexFilterRequest.php
Normal file
60
app/Http/Requests/Products/IndexFilterRequest.php
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Products;
|
||||||
|
|
||||||
|
use App\Enums\Products\CertificationEnum;
|
||||||
|
use App\Enums\Products\ClaimEnum;
|
||||||
|
use App\Enums\Products\DistributionNetworkEnum;
|
||||||
|
use App\Enums\Products\GeoAreaEnum;
|
||||||
|
use App\Enums\Products\OriginEnum;
|
||||||
|
use App\Enums\Products\RangeEnum;
|
||||||
|
use App\Enums\Products\RayEnum;
|
||||||
|
use App\Enums\Products\SourceEnum;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rules\Enum;
|
||||||
|
|
||||||
|
class IndexFilterRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'nullable|string',
|
||||||
|
'brand_id' => 'nullable|exists:brands,id',
|
||||||
|
'gencod' => 'nullable|string',
|
||||||
|
|
||||||
|
'source' => ['nullable', new Enum(SourceEnum::class)],
|
||||||
|
'shop' => 'nullable|string',
|
||||||
|
'fair' => 'nullable|string',
|
||||||
|
'catalogue' => 'nullable|string',
|
||||||
|
'claims' => 'nullable|array',
|
||||||
|
'claims.*' => ['required', new Enum(ClaimEnum::class)],
|
||||||
|
'specified_claim' => 'nullable|string',
|
||||||
|
'origins' => 'nullable|array',
|
||||||
|
'origins.*' => ['required', new Enum(OriginEnum::class)],
|
||||||
|
'certification' => ['nullable', new Enum(CertificationEnum::class)],
|
||||||
|
'distribution_network' => ['nullable', new Enum(DistributionNetworkEnum::class)],
|
||||||
|
'ray' => ['nullable', new Enum(RayEnum::class)],
|
||||||
|
'product_range' => ['nullable', new Enum(RangeEnum::class)],
|
||||||
|
'geo_area' => ['nullable', new Enum(GeoAreaEnum::class)],
|
||||||
|
'keywords' => 'nullable|array',
|
||||||
|
'keywords.*' => 'required|exists:keywords,id',
|
||||||
|
'date_before' => 'nullable|date:Y-m-d',
|
||||||
|
'date_after' => 'nullable|date:Y-m-d',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
160
app/Http/Requests/Products/StoreProductRequest.php
Normal file
160
app/Http/Requests/Products/StoreProductRequest.php
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Products;
|
||||||
|
|
||||||
|
use App\Enums\Products\CertificationEnum;
|
||||||
|
use App\Enums\Products\ClaimEnum;
|
||||||
|
use App\Enums\Products\DistributionNetworkEnum;
|
||||||
|
use App\Enums\Products\GeoAreaEnum;
|
||||||
|
use App\Enums\Products\OriginEnum;
|
||||||
|
use App\Enums\Products\RangeEnum;
|
||||||
|
use App\Enums\Products\RayEnum;
|
||||||
|
use App\Enums\Products\SourceEnum;
|
||||||
|
use App\Lib\Helpers\ToolboxHelper;
|
||||||
|
use App\Traits\Requests\HasDocumentAndPictureList;
|
||||||
|
use App\Traits\Requests\HasPicture;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rules\Enum;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class StoreProductRequest extends FormRequest
|
||||||
|
{
|
||||||
|
use HasPicture;
|
||||||
|
use HasDocumentAndPictureList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the data for validation.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function prepareForValidation()
|
||||||
|
{
|
||||||
|
$this->merge([
|
||||||
|
'id' => $this->route('product')->id ?? null,
|
||||||
|
'is_tasted' => $this->is_tasted ? true : false,
|
||||||
|
'origins' => $this->origins ? $this->origins : [],
|
||||||
|
'claims' => $this->claims ? $this->claims : [],
|
||||||
|
'picture_alt' => $this->name,
|
||||||
|
'picture_title' => $this->name,
|
||||||
|
'certification' => $this->certification == 0 ? null : $this->certification,
|
||||||
|
]);
|
||||||
|
$this->mergePicture('picture');
|
||||||
|
$this->mergeDocuments('docs');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'name' => 'required|string|min:3|max:255',
|
||||||
|
'brand_id' => 'required|exists:brands,id',
|
||||||
|
'source' => [new Enum(SourceEnum::class)],
|
||||||
|
'fair' => 'nullable|string|min:3|max:255',
|
||||||
|
'shop' => 'nullable|string|min:3|max:255',
|
||||||
|
'catalogue' => 'nullable|string|min:3|max:255',
|
||||||
|
'gencod' => 'nullable|numeric|min:0',
|
||||||
|
'picture_alt' => 'required|min:3|max:255',
|
||||||
|
'picture_title' => 'required|min:3|max:255',
|
||||||
|
'url' => [
|
||||||
|
'nullable', 'url', function ($attribute, string $value, $fail) {
|
||||||
|
try {
|
||||||
|
ToolboxHelper::assertNoInternalBoUrls($attribute, $value);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$fail(\trans('Impossible d\'utiliser une url du back-office.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'certification' => ['nullable', new Enum(CertificationEnum::class)],
|
||||||
|
'origins' => 'present|array',
|
||||||
|
'origins.*' => [new Enum(OriginEnum::class)],
|
||||||
|
'claims' => 'present|array',
|
||||||
|
'claims.*' => [new Enum(ClaimEnum::class)],
|
||||||
|
'specified_claim' => 'string|min:3|max:255|required_if:claims,' . ClaimEnum::others->value,
|
||||||
|
'distribution_network' => ['required', new Enum(DistributionNetworkEnum::class)],
|
||||||
|
'ray' => ['required', new Enum(RayEnum::class)],
|
||||||
|
'product_range' => ['required', new Enum(RangeEnum::class)],
|
||||||
|
'geo_area' => ['required', new Enum(GeoAreaEnum::class)],
|
||||||
|
'weight' => 'nullable|integer',
|
||||||
|
'pvc' => 'nullable|decimal:0,2',
|
||||||
|
'comment' => 'nullable|string|min:15',
|
||||||
|
'is_tasted' => 'required|boolean',
|
||||||
|
'tasters_number' => 'nullable|integer',
|
||||||
|
'evaluation' => 'nullable|array',
|
||||||
|
'evaluation.*' => 'sometimes|string|min:3|max:255',
|
||||||
|
'aspect' => 'nullable|array',
|
||||||
|
'aspect.*' => 'nullable|string|min:3|max:255',
|
||||||
|
'taste' => 'nullable|array',
|
||||||
|
'taste.*' => 'nullable|string|min:3|max:255',
|
||||||
|
'odor' => 'nullable|array',
|
||||||
|
'odor.*' => 'nullable|string|min:3|max:255',
|
||||||
|
'texture' => 'nullable|array',
|
||||||
|
'texture.*' => 'nullable|string|min:3|max:255',
|
||||||
|
];
|
||||||
|
return \array_merge(
|
||||||
|
$rules,
|
||||||
|
$this->pictureRules('picture', false, 1200, 900, 1200, 900),
|
||||||
|
$this->documentsRules('docs'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get custom attributes for validator errors.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function attributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => trans('nom du produit'),
|
||||||
|
'brand_id' => trans('marque du produit'),
|
||||||
|
'source' => trans('source du produit'),
|
||||||
|
'fair' => trans('salon du produit'),
|
||||||
|
'shop' => trans('magazin du produit'),
|
||||||
|
'catalogue' => trans('catalogue du produit'),
|
||||||
|
'gencod' => trans('gencod du produit'),
|
||||||
|
'picture_alt' => trans('attribut alt du produit'),
|
||||||
|
'picture_title' => trans('attribut titre du produit'),
|
||||||
|
'docs' => trans('documents du produit'),
|
||||||
|
'url' => trans('lien du produit'),
|
||||||
|
'certification' => trans('certification'),
|
||||||
|
'origins' => trans('origines du produit'),
|
||||||
|
'origins.*' => trans('origine du produit'),
|
||||||
|
'claims' => trans('allégations du produit'),
|
||||||
|
'claims.*' => trans('allégation du produit'),
|
||||||
|
'specified_claim' => trans('allégation spécifique du produit'),
|
||||||
|
'distribution_network' => trans('réseau de distribution du produit'),
|
||||||
|
'ray' => trans('rayon du produit'),
|
||||||
|
'product_range' => trans('famille du produit'),
|
||||||
|
'geo_area' => trans('zone géographique du produit'),
|
||||||
|
'weight' => trans('poids du produit'),
|
||||||
|
'pvc' => trans('pvc de l\'uvc du produit'),
|
||||||
|
'comment' => trans('commentaire du produit'),
|
||||||
|
'is_tasted' => trans('produit dégusté ?'),
|
||||||
|
'tasters_number' => trans('nombre de dégustateurs du produit'),
|
||||||
|
'evaluation' => trans('évaluations du produit (partie commentaire)'),
|
||||||
|
'evaluation.*' => trans('évaluation du produit (partie commentaire)'),
|
||||||
|
'aspect' => trans('aspects du produit (partie commentaire)'),
|
||||||
|
'aspect.*' => trans('aspect du produit (partie commentaire)'),
|
||||||
|
'taste' => trans('goûts du produit (partie commentaire)'),
|
||||||
|
'taste.*' => trans('goût du produit (partie commentaire)'),
|
||||||
|
'odor' => trans('odeurs du produit (partie commentaire)'),
|
||||||
|
'odor.*' => trans('odeur du produit (partie commentaire)'),
|
||||||
|
'texture' => trans('textures du produit (partie commentaire)'),
|
||||||
|
'texture.*' => trans('texture du produit (partie commentaire)'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Http/Requests/Products/UpdateProductRequest.php
Normal file
7
app/Http/Requests/Products/UpdateProductRequest.php
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Products;
|
||||||
|
|
||||||
|
class UpdateProductRequest extends StoreProductRequest
|
||||||
|
{
|
||||||
|
}
|
||||||
117
app/Http/Resources/ProductResource.php
Normal file
117
app/Http/Resources/ProductResource.php
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use App\Enums\Products\ClaimEnum;
|
||||||
|
use App\Enums\Products\OriginEnum;
|
||||||
|
use App\Models\Keyword;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\ProductComment;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class ProductResource extends JsonResource
|
||||||
|
{
|
||||||
|
/** @var \App\Models\Product */
|
||||||
|
private $product;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private static $skeleton = [
|
||||||
|
'id' => null,
|
||||||
|
'user' => null,
|
||||||
|
'brand' => null,
|
||||||
|
'name' => null,
|
||||||
|
'seen_at' => null,
|
||||||
|
'source' => null,
|
||||||
|
'fair' => null,
|
||||||
|
'shop' => null,
|
||||||
|
'catalogue' => null,
|
||||||
|
'gencod' => null,
|
||||||
|
'weight' => null,
|
||||||
|
'pvc' => null,
|
||||||
|
'picture' => null,
|
||||||
|
'picture_alt' => null,
|
||||||
|
'picture_title' => null,
|
||||||
|
'certification' => null,
|
||||||
|
'origins' => null,
|
||||||
|
'claims' => null,
|
||||||
|
'specified_claim' => null,
|
||||||
|
'distribution_network' => null,
|
||||||
|
'ray' => null,
|
||||||
|
'product_range' => null,
|
||||||
|
'geo_area' => null,
|
||||||
|
'freeComment' => null,
|
||||||
|
'productComments' => null,
|
||||||
|
'productKeywords' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProductResource
|
||||||
|
*
|
||||||
|
* @param \App\Models\Product $product
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Product $product)
|
||||||
|
{
|
||||||
|
$this->product = $product;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request|null $request
|
||||||
|
* @return array
|
||||||
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||||
|
*/
|
||||||
|
public function toArray($request = null)
|
||||||
|
{
|
||||||
|
return array_intersect_key(
|
||||||
|
[
|
||||||
|
'id' => $this->product->id,
|
||||||
|
'user' => (object)$this->product->user->toArray(),
|
||||||
|
'brand' => (object)$this->product->brand->toArray(),
|
||||||
|
'name' => $this->product->name,
|
||||||
|
'seen_at' => $this->product->seen_at->isoFormat('DD\/MM\/YYYY'),
|
||||||
|
'source' => $this->product->source->label(),
|
||||||
|
'fair' => $this->product->fair,
|
||||||
|
'shop' => $this->product->shop,
|
||||||
|
'catalogue' => $this->product->catalogue,
|
||||||
|
'gencod' => $this->product->gencod,
|
||||||
|
'weight' => $this->product->weight,
|
||||||
|
'pvc' => $this->product->pvc,
|
||||||
|
'picture' => $this->product->picture,
|
||||||
|
'picture_alt' => $this->product->picture_alt,
|
||||||
|
'picture_title' => $this->product->picture_title,
|
||||||
|
'certification' => \optional($this->product->certification)->label(),
|
||||||
|
'origins' => $this->product->origins_enum->map(fn (OriginEnum $enum) => $enum->label())->implode(', '),
|
||||||
|
'claims' => $this->product->claims_enum->map(fn (ClaimEnum $enum) => $enum->label())->implode(', '),
|
||||||
|
'specified_claim' => $this->product->specified_claim,
|
||||||
|
'distribution_network' => $this->product->distribution_network->label(),
|
||||||
|
'ray' => $this->product->ray->label(),
|
||||||
|
'product_range' => $this->product->product_range->label(),
|
||||||
|
'geo_area' => $this->product->geo_area->label(),
|
||||||
|
'freeComment' => $this->product->comment,
|
||||||
|
// FIXME: Use dedicaced resources for relations.
|
||||||
|
'productComments' => $this->product->productComments->map(function (ProductComment $comment) {
|
||||||
|
return (object)\array_merge($comment->toArray(), [
|
||||||
|
'created_at' => $comment->created_at->isoFormat('DD\/MM\/YYYY'),
|
||||||
|
'updated_at' => $comment->updated_at->isoFormat('DD\/MM\/YYYY'),
|
||||||
|
]);
|
||||||
|
}),
|
||||||
|
'productKeywords' => $this->product->productKeywords
|
||||||
|
->map(fn (Keyword $keyword) => $keyword->label)
|
||||||
|
->implode(', '),
|
||||||
|
],
|
||||||
|
$this->getSkeleton()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resource skeletton
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getSkeleton(): array
|
||||||
|
{
|
||||||
|
return self::$skeleton;
|
||||||
|
}
|
||||||
|
}
|
||||||
81
app/Jobs/ExportProduct.php
Normal file
81
app/Jobs/ExportProduct.php
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\Product;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class ExportProduct implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
use InteractsWithQueue;
|
||||||
|
use Queueable;
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @param integer $productId
|
||||||
|
* @return void
|
||||||
|
* @throws \Error If file storage config is wrong.
|
||||||
|
* @throws \RuntimeException If the storage disk export is not local file system.
|
||||||
|
*/
|
||||||
|
public function __construct(int $productId)
|
||||||
|
{
|
||||||
|
/** @var \App\Models\Product $product */
|
||||||
|
$product = Product::query()->where('id', intval($productId))->firstOrFail();
|
||||||
|
|
||||||
|
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||||
|
$exportDisk = Storage::disk('export');
|
||||||
|
|
||||||
|
if (!($exportDisk instanceof \Illuminate\Filesystem\FilesystemAdapter)) {
|
||||||
|
throw new \Error('Storage disk export has to be local file system');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$exportDisk->directoryExists('export-product')) {
|
||||||
|
$exportDisk->createDirectory('export-product');
|
||||||
|
}
|
||||||
|
|
||||||
|
// * Create zip
|
||||||
|
$zip = new \ZipArchive();
|
||||||
|
$fileName = date('d-m-Y') . '-' . Str::uuid() . '.zip';
|
||||||
|
|
||||||
|
if (!$zip->open($exportDisk->path("export-product/{$fileName}"), \ZipArchive::CREATE) === true) {
|
||||||
|
throw new \RuntimeException("The ZIP file cannot be created.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$dirName = Str::slug(
|
||||||
|
Carbon::parse($product->updated_at)->format('y-m-d') . '-' .
|
||||||
|
$product->user->lastname . '-' . $product->user->id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$zip->addEmptyDir($dirName)) {
|
||||||
|
throw new \RuntimeException("The folder cannot be created inside the ZIP.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// * Add files
|
||||||
|
$pdf = Product::generateProductPdf($product, "test");
|
||||||
|
$exportDisk->put('pdf/' . $product->id . '.pdf', $pdf->output());
|
||||||
|
$zip->addFile($exportDisk->path('pdf/' . $product->id . '.pdf'), $dirName . "/" . $product->name . ".pdf");
|
||||||
|
$zip->addFile($product->picture, $dirName . "/photo." . pathinfo($product->picture, PATHINFO_EXTENSION));
|
||||||
|
foreach ($product->docs as $doc) {
|
||||||
|
$zip->addFile($doc, $dirName . "/document." . pathinfo($doc, PATHINFO_EXTENSION));
|
||||||
|
}
|
||||||
|
|
||||||
|
// * Save zip
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
|
if (!$exportDisk->exists("export-product/{$fileName}")) {
|
||||||
|
throw new \RuntimeException("The ZIP file 'export-product/{$fileName}' has not been created.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Product::downloadPrivateExportFile("export-product/{$fileName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
425
app/Lib/Helpers/FileStorageHelper.php
Normal file
425
app/Lib/Helpers/FileStorageHelper.php
Normal file
|
|
@ -0,0 +1,425 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Lib\Helpers;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to handle files in LDC Laravel stack
|
||||||
|
*
|
||||||
|
* * The storage strategy will be using date.
|
||||||
|
* The file name may contain sufix timestamp highresolution time (hrtime or microtime) if is duplicate.
|
||||||
|
* (function() { return time() . ' ' . Str::slug(microtime(true)) . ' ' . hrtime(true); })();
|
||||||
|
*
|
||||||
|
* posts/ - The model table name
|
||||||
|
* 10/ - Year
|
||||||
|
* 04/ - Month
|
||||||
|
* 19/ - Day
|
||||||
|
* 5f/ - First two letters of md5 file
|
||||||
|
* black-cat-under-red-car.png - Slugified file name
|
||||||
|
* black-cat-under-red-car-286071690833400.png - Slugified file name that is duplicated
|
||||||
|
*
|
||||||
|
* The final path will be storage/modelfiles/posts/10/04/19/5f/black-cat-under-red-car-286071690833400.png
|
||||||
|
*
|
||||||
|
* ! No limits of file per folder will be handled.
|
||||||
|
*
|
||||||
|
* @author Munsch Jérémy <jeremy.munsch@ldc.fr>
|
||||||
|
*/
|
||||||
|
class FileStorageHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Destroy the file associate with the attribute.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Model $model
|
||||||
|
* @param string $attribute
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function removeFile(Model $model, string $attribute): void
|
||||||
|
{
|
||||||
|
$path = \ltrim(\urldecode($model->{$attribute}), '/');
|
||||||
|
if (\strpos($path, 'storage') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$path = ToolboxHelper::mbReplace('storage/', '', $path);
|
||||||
|
if (Storage::disk('public')->exists($path)) {
|
||||||
|
Storage::disk('public')->delete($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the file associate with the attribute old value (before updated to DB).
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Model $model
|
||||||
|
* @param string $attribute
|
||||||
|
* @param boolean $onlyIfUpdated
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function removeOldFile(Model $model, string $attribute, bool $onlyIfUpdated = true): void
|
||||||
|
{
|
||||||
|
// * Ignore If removal has to be done only if the field has changed and it actually hasnt.
|
||||||
|
if ($onlyIfUpdated and $model->{$attribute} === $model->getOriginal($attribute)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$originalPath = \ltrim(\urldecode($model->getOriginal($attribute)), '/');
|
||||||
|
if (\strpos($originalPath, 'storage') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
|
||||||
|
if (Storage::disk('public')->exists($originalPath)) {
|
||||||
|
Storage::disk('public')->delete($originalPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a file using optimized storage strategy
|
||||||
|
*
|
||||||
|
* You can use filename param to overload file name.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Model $model The model that will hold the picture.
|
||||||
|
* @param \Illuminate\Http\UploadedFile|\SplFileInfo|string $file The file, will just return itself is string.
|
||||||
|
* @param boolean $slugify Force filename slugification.
|
||||||
|
* @param string|null $filename This string may be used to store the file.
|
||||||
|
* @return string
|
||||||
|
* @throws \RuntimeException If file copy fails.
|
||||||
|
*/
|
||||||
|
public static function storeFile(Model $model, $file, bool $slugify = false, string $filename = null): string
|
||||||
|
{
|
||||||
|
$tableName = $model->getTable();
|
||||||
|
if (\is_object($file) and $file instanceof \Illuminate\Http\UploadedFile) {
|
||||||
|
/** @var \Illuminate\Http\UploadedFile $file */
|
||||||
|
$filename = $filename ?: $file->getClientOriginalName();
|
||||||
|
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
|
||||||
|
$newPath = self::prepareMoveFile($tableName, $filename);
|
||||||
|
$newPath = str_replace(storage_path('app'), '', $newPath);
|
||||||
|
$file->storePubliclyAs(
|
||||||
|
pathinfo($newPath, \PATHINFO_DIRNAME),
|
||||||
|
pathinfo($newPath, \PATHINFO_BASENAME)
|
||||||
|
);
|
||||||
|
return 'storage' . str_replace('/public', '', $newPath);
|
||||||
|
}
|
||||||
|
if (\is_object($file) and $file instanceof \SplFileInfo) {
|
||||||
|
/** @var \SplFileInfo $file */
|
||||||
|
$filename = $filename ?: $file->getBaseName();
|
||||||
|
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
|
||||||
|
$newPath = self::prepareMoveFile($tableName, $filename);
|
||||||
|
if (!File::copy($file->getRealPath(), $newPath)) {
|
||||||
|
throw new \RuntimeException(sprintf(
|
||||||
|
'Failed to copy file %s to %s',
|
||||||
|
$file->getRealPath(),
|
||||||
|
$newPath
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return \ltrim(str_replace(\storage_path('app/public'), '/storage', $newPath), '/');
|
||||||
|
}
|
||||||
|
return strval($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store all files from string attribute html
|
||||||
|
* If oldHtmlString is passed, a diff is done with new and old files
|
||||||
|
* to keep only files that are present in the new html string.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Model $model The model that will hold the picture.
|
||||||
|
* @param string $htmlString The html string to parse and modify files.
|
||||||
|
* @param string|null $oldHtmlString The old html string with alreadyParsed
|
||||||
|
* files using storeModelFilesFromHtml.
|
||||||
|
* @return string Html with files pathes replaced using storage strategy.
|
||||||
|
*/
|
||||||
|
public static function storeModelFilesFromHtml(
|
||||||
|
Model $model,
|
||||||
|
string $htmlString,
|
||||||
|
string $oldHtmlString = null
|
||||||
|
): string {
|
||||||
|
\collect(self::onlyUploadedFilesWithFileManager(self::findFilesInHtml($htmlString)))
|
||||||
|
->each(function (string $path) use ($model, &$htmlString) {
|
||||||
|
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||||
|
$disk = Storage::disk('uploads');
|
||||||
|
$fileInfo = new \SplFileInfo($disk->path(
|
||||||
|
ToolboxHelper::mbReplace('/uploads/', '', \urldecode($path))
|
||||||
|
));
|
||||||
|
$htmlString = ToolboxHelper::mbReplace(
|
||||||
|
$path,
|
||||||
|
'/' . self::storeFile($model, $fileInfo, true),
|
||||||
|
$htmlString
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($oldHtmlString) {
|
||||||
|
self::removeOldModelFilesFromHtml($htmlString, $oldHtmlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $htmlString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all old files from string attribute html that are stored in public that
|
||||||
|
* are nove present anymore on new html string
|
||||||
|
*
|
||||||
|
* @param string $newHtmlString The html string with alreadyParsed files using storeModelFilesFromHtml.
|
||||||
|
* @param string $oldHtmlString The old html string with alreadyParsed files using storeModelFilesFromHtml.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function removeOldModelFilesFromHtml(string $newHtmlString, string $oldHtmlString): void
|
||||||
|
{
|
||||||
|
self::removeOldFiles(self::findFilesInHtml($oldHtmlString), self::findFilesInHtml($newHtmlString));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all old files that are stored in public that
|
||||||
|
* are not present anymore on new array files
|
||||||
|
*
|
||||||
|
* @param string[] $oldFiles The old array files.
|
||||||
|
* @param string[] $newFiles The new array files.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function removeOldFiles(array $oldFiles, array $newFiles): void
|
||||||
|
{
|
||||||
|
$oldFiles = \collect(self::onlyUploadedFilesWithFileStorageHelper($oldFiles));
|
||||||
|
$filesToKeep = \collect(self::onlyUploadedFilesWithFileStorageHelper($newFiles));
|
||||||
|
$filesToRemove = $oldFiles->diff($filesToKeep);
|
||||||
|
$filesToRemove->each(function (string $publicStorageFilePath) {
|
||||||
|
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
|
||||||
|
if (Storage::disk('public')->exists($path)) {
|
||||||
|
Storage::disk('public')->delete($path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all files from string attribute html that are stored in public
|
||||||
|
*
|
||||||
|
* @param string $htmlString The html string with alreadyParsed files using storeModelFilesFromHtml.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function removeModelFilesOfHtml(string $htmlString): void
|
||||||
|
{
|
||||||
|
$filesToRemove = \collect(self::onlyUploadedFilesWithFileStorageHelper(self::findFilesInHtml($htmlString)));
|
||||||
|
$filesToRemove->each(function (string $publicStorageFilePath) {
|
||||||
|
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
|
||||||
|
if (Storage::disk('public')->exists($path)) {
|
||||||
|
Storage::disk('public')->delete($path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all occurence of files in html
|
||||||
|
* @param string $html
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function findFilesInHtml(string $html): array
|
||||||
|
{
|
||||||
|
preg_match_all('/href="(?P<href>.*)"|src="(?P<src>.*)"|url="(?P<url>.*)"/Um', $html, $m, PREG_SET_ORDER, 0);
|
||||||
|
return collect($m)->pluck('href')->filter()
|
||||||
|
->concat(collect($m)->pluck('url')->filter())
|
||||||
|
->concat(collect($m)->pluck('src')->filter())
|
||||||
|
->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter array to get only uploaded files that exists
|
||||||
|
* on disk 'public' (using helper storage strategy)
|
||||||
|
*
|
||||||
|
* @param array $urls
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function onlyUploadedFilesWithFileStorageHelper(array $urls): array
|
||||||
|
{
|
||||||
|
return \collect($urls)->unique()
|
||||||
|
// * Filter to get only /uploads and using app url or empty
|
||||||
|
->filter(function (string $url) {
|
||||||
|
$path = \parse_url($url, \PHP_URL_PATH);
|
||||||
|
return \strpos(\ltrim($path, '/'), 'storage/modelfiles') === 0;
|
||||||
|
})->filter(function (string $url) {
|
||||||
|
$path = \parse_url($url, \PHP_URL_PATH);
|
||||||
|
return Storage::disk('public')
|
||||||
|
->exists(ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($path), '/')));
|
||||||
|
})->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter array to get only uploaded files that exists
|
||||||
|
* on disk 'uploads'
|
||||||
|
*
|
||||||
|
* @param array $urls
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function onlyUploadedFilesWithFileManager(array $urls): array
|
||||||
|
{
|
||||||
|
return \collect($urls)->unique()
|
||||||
|
// * Filter to get only /uploads and using app url or empty
|
||||||
|
->filter(function (string $url) {
|
||||||
|
$host = \parse_url($url, \PHP_URL_HOST);
|
||||||
|
$path = \parse_url($url, \PHP_URL_PATH);
|
||||||
|
return ($host === \parse_url(config('app.url'), PHP_URL_HOST) or \is_null($host)) and
|
||||||
|
\strpos(\ltrim($path, '/'), 'uploads') === 0;
|
||||||
|
})->filter(function (string $url) {
|
||||||
|
$path = \parse_url($url, \PHP_URL_PATH);
|
||||||
|
return Storage::disk('uploads')
|
||||||
|
->exists(ToolboxHelper::mbReplace('uploads/', '', \ltrim(\urldecode($path), '/')));
|
||||||
|
})->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare storage path and return
|
||||||
|
* the file full path
|
||||||
|
*
|
||||||
|
* @param string $tableName Model table name.
|
||||||
|
* @param string $filename The basename for the file.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function prepareMoveFile(string $tableName, string $filename): string
|
||||||
|
{
|
||||||
|
// * Security filter + beautifier
|
||||||
|
$filename = self::sanitizeFileName($filename);
|
||||||
|
// * Security filter
|
||||||
|
$filename = \filter_var($filename, \FILTER_SANITIZE_STRING);
|
||||||
|
// * Slugify filename
|
||||||
|
$ext = \pathinfo($filename, \PATHINFO_EXTENSION);
|
||||||
|
$filename = Str::slug(\pathinfo($filename, \PATHINFO_FILENAME)) .
|
||||||
|
(\strlen($ext) ? ".{$ext}" : '');
|
||||||
|
|
||||||
|
$folderPath = self::getStoragePath($tableName, $filename);
|
||||||
|
$filename = self::getFileUniqueName($folderPath, $filename);
|
||||||
|
return "{$folderPath}/{$filename}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create sub folders to store files using pattern
|
||||||
|
* storage/modelfiles/posts/10/04/19/5f
|
||||||
|
* year/month/day/md5 first 2 letters
|
||||||
|
*
|
||||||
|
* @param string $table
|
||||||
|
* @param string $filename
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function getStoragePath(string $table, string $filename): string
|
||||||
|
{
|
||||||
|
$filenameHash = \md5($filename);
|
||||||
|
$pathFolder = \storage_path(sprintf(
|
||||||
|
'app/public/modelfiles/%s/%s/%s/%s/%s',
|
||||||
|
$table,
|
||||||
|
gmdate('y'),
|
||||||
|
gmdate('m'),
|
||||||
|
gmdate('d'),
|
||||||
|
substr($filenameHash, 0, 2)
|
||||||
|
));
|
||||||
|
if (!File::exists($pathFolder)) {
|
||||||
|
File::makeDirectory($pathFolder, 0755, true);
|
||||||
|
}
|
||||||
|
return $pathFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unique filename if the path is already occupied
|
||||||
|
*
|
||||||
|
* @param string $folderPath
|
||||||
|
* @param string $filename
|
||||||
|
* @return string
|
||||||
|
* @throws \RuntimeException If a unique filename cannot be obtained.
|
||||||
|
*/
|
||||||
|
private static function getFileUniqueName(string $folderPath, string $filename): string
|
||||||
|
{
|
||||||
|
$attempts = 0;
|
||||||
|
$maxAttempts = 20;
|
||||||
|
while (File::exists("{$folderPath}/{$filename}")) {
|
||||||
|
if ($attempts++ >= $maxAttempts) {
|
||||||
|
throw new \RuntimeException("Failed to has a unique filename for {$folderPath}/{$filename}");
|
||||||
|
}
|
||||||
|
$filename = pathinfo($filename, \PATHINFO_FILENAME) .
|
||||||
|
\uniqid('-') . '.' .
|
||||||
|
pathinfo($filename, \PATHINFO_EXTENSION);
|
||||||
|
}
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slugify the filename
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function slugifyFileName(string $filename): string
|
||||||
|
{
|
||||||
|
return Str::slug(pathinfo($filename, \PATHINFO_FILENAME)) . '.' . pathinfo($filename, \PATHINFO_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize File name for uploaded files
|
||||||
|
*
|
||||||
|
* @param string $filename The original uploaded client file name.
|
||||||
|
* @param boolean $beautify Beautify the filename.
|
||||||
|
* @return string The sanitized file name.
|
||||||
|
*/
|
||||||
|
public static function sanitizeFileName(string $filename, bool $beautify = true): string
|
||||||
|
{
|
||||||
|
// * Sanitize filename
|
||||||
|
// phpcs:disable Generic.Files.LineLength.TooLong
|
||||||
|
$filename = preg_replace(
|
||||||
|
'~
|
||||||
|
[<>:"/\\\|?*]| # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
|
||||||
|
[\x00-\x1F]| # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
|
||||||
|
[\x7F\xA0\xAD]| # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN
|
||||||
|
[#\[\]@!$&\'()+,;=]| # URI reserved https://tools.ietf.org/html/rfc3986#section-2.2
|
||||||
|
[{}^\~`] # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt
|
||||||
|
~x',
|
||||||
|
'-',
|
||||||
|
$filename
|
||||||
|
);
|
||||||
|
// phpcs:enable
|
||||||
|
// * Avoids '.' '..' or '.hiddenFiles' .
|
||||||
|
$filename = Str::of($filename)->ltrim('.-');
|
||||||
|
// * Optional beautification
|
||||||
|
if ($beautify) {
|
||||||
|
$filename = static::beautifyFilename($filename);
|
||||||
|
}
|
||||||
|
// * Maximize filename length to 255 bytes http://serverfault.com/a/9548/44086
|
||||||
|
/** @var string */
|
||||||
|
$extension = pathinfo($filename, \PATHINFO_EXTENSION);
|
||||||
|
/** @var string */
|
||||||
|
$filename = pathinfo($filename, \PATHINFO_FILENAME);
|
||||||
|
|
||||||
|
$encoding = mb_detect_encoding($filename);
|
||||||
|
$encoding = $encoding ? $encoding : null;
|
||||||
|
return \mb_strcut(
|
||||||
|
$filename,
|
||||||
|
0,
|
||||||
|
255 - (!empty($extension) ? strlen($extension) + 1 : 0),
|
||||||
|
$encoding
|
||||||
|
) . (!empty($extension) ? ".$extension" : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beautify a filename
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function beautifyFilename(string $filename): string
|
||||||
|
{
|
||||||
|
// Reduce consecutive characters.
|
||||||
|
$filename = preg_replace([
|
||||||
|
// * "file name.zip" becomes 'file-name.zip'
|
||||||
|
'/ +/',
|
||||||
|
// * "file___name.zip" becomes 'file-name.zip'
|
||||||
|
'/_+/',
|
||||||
|
// * "file---name.zip" becomes 'file-name.zip'
|
||||||
|
'/-+/'
|
||||||
|
], '-', $filename);
|
||||||
|
$filename = preg_replace([
|
||||||
|
// * "file--.--.-.--name.zip" becomes "file.name.zip"
|
||||||
|
'/-*\.-*/',
|
||||||
|
// * "file...name..zip" becomes "file.name.zip"
|
||||||
|
'/\.{2,}/'
|
||||||
|
], '.', $filename);
|
||||||
|
// Lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625 .
|
||||||
|
$filename = mb_strtolower($filename, mb_detect_encoding($filename));
|
||||||
|
// * ".file-name.-" becomes "file-name"
|
||||||
|
$filename = trim($filename, '.-');
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
248
app/Lib/Helpers/ToolboxHelper.php
Normal file
248
app/Lib/Helpers/ToolboxHelper.php
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Lib\Helpers;
|
||||||
|
|
||||||
|
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Validation\Rules\Enum;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
class ToolboxHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Cut string words
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @param integer $max
|
||||||
|
* @param string $hyphen
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function cutWords(string $string, int $max = 20, string $hyphen = '[.]')
|
||||||
|
{
|
||||||
|
$originalString = $string;
|
||||||
|
$tok = strtok($string, ' ');
|
||||||
|
$string = '';
|
||||||
|
while ($tok !== false && mb_strlen($string) < $max) {
|
||||||
|
if (
|
||||||
|
mb_strlen($string) + mb_strlen($tok) <= $max
|
||||||
|
) {
|
||||||
|
$string .= $tok . ' ';
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$tok = strtok(' ');
|
||||||
|
}
|
||||||
|
return trim($string) . (strlen(trim($string)) !== strlen(trim($originalString)) ? $hyphen : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip scheme (https) on oembed urls
|
||||||
|
* Only embed allowed are for MP4 self hosted videos right now
|
||||||
|
*
|
||||||
|
* https is force by ckeditor MediaElements which natively supports
|
||||||
|
* only cloud hosted medias (youtube, spotify etc..)
|
||||||
|
*
|
||||||
|
* @param string $input
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function stripCkEditorSchemesOnMediaInputs(string $input): string
|
||||||
|
{
|
||||||
|
$input = \preg_replace('/(?<=<oembed url=")(https:\/\/)(?=.*?">)/m', '', $input);
|
||||||
|
return $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert That no Back Office url is present on txt
|
||||||
|
*
|
||||||
|
* @param string $field
|
||||||
|
* @param string $text
|
||||||
|
* @return string
|
||||||
|
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
|
||||||
|
*/
|
||||||
|
public static function assertNoInternalBoUrls(string $field, string $text): string
|
||||||
|
{
|
||||||
|
$routes = Route::getRoutes();
|
||||||
|
// * Url replace and email replace.
|
||||||
|
$text = preg_replace_callback(
|
||||||
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||||
|
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
|
||||||
|
function ($matches) use ($routes, $field) {
|
||||||
|
$match = collect($matches)->first() ?? '';
|
||||||
|
$url = $match;
|
||||||
|
try {
|
||||||
|
$request = Request::create($url);
|
||||||
|
// If a route is match then it do not throws exception.
|
||||||
|
if (
|
||||||
|
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
|
||||||
|
trim($routes->match($request)->getPrefix() ?? '', '/') === 'bo'
|
||||||
|
) {
|
||||||
|
// Removes the matched url.
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
$field => ':attribute : Il est interdit de coller une url du back office dans ce champ'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return $match;
|
||||||
|
} catch (NotFoundHttpException $e) {
|
||||||
|
return $match;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert That only external url is present on txt
|
||||||
|
*
|
||||||
|
* @param string $field
|
||||||
|
* @param string $text
|
||||||
|
* @return string
|
||||||
|
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
|
||||||
|
*/
|
||||||
|
public static function assertNoInternalUrls(string $field, string $text): string
|
||||||
|
{
|
||||||
|
self::assertNoInternalBoUrls($field, $text);
|
||||||
|
$routes = Route::getRoutes();
|
||||||
|
// * Url replace and email replace.
|
||||||
|
$text = preg_replace_callback(
|
||||||
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||||
|
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
|
||||||
|
function ($matches) use ($routes, $field) {
|
||||||
|
$match = collect($matches)->first() ?? '';
|
||||||
|
$url = $match;
|
||||||
|
try {
|
||||||
|
$request = Request::create($url);
|
||||||
|
// If a route is match then it do not throws exception.
|
||||||
|
if (
|
||||||
|
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
|
||||||
|
$routes->match($request)
|
||||||
|
) {
|
||||||
|
// Removes the matched url.
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
$field => sprintf(
|
||||||
|
':attribute : Il est interdit de coller une url de %s dans ce champ',
|
||||||
|
config('app.name')
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return $match;
|
||||||
|
} catch (NotFoundHttpException $e) {
|
||||||
|
return $match;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutltibyte string replace
|
||||||
|
* @param string|array $search
|
||||||
|
* @param string|array $replace
|
||||||
|
* @param mixed $subject
|
||||||
|
* @param integer $count
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function mbReplace(string|array $search, string|array $replace, mixed $subject, int &$count = 0)
|
||||||
|
{
|
||||||
|
if (!is_array($search) && is_array($replace)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (is_array($subject)) {
|
||||||
|
// Call mb_replace for each single string in $subject .
|
||||||
|
foreach ($subject as &$string) {
|
||||||
|
$string = &self::mbReplace($search, $replace, $string, $count);
|
||||||
|
}
|
||||||
|
} elseif (is_array($search)) {
|
||||||
|
if (!is_array($replace)) {
|
||||||
|
foreach ($search as &$string) {
|
||||||
|
$subject = self::mbReplace($string, $replace, $subject, $count);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$n = max(count($search), count($replace));
|
||||||
|
while ($n--) {
|
||||||
|
$subject = self::mbReplace(current($search), current($replace), $subject, $count);
|
||||||
|
next($search);
|
||||||
|
next($replace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$parts = mb_split(preg_quote($search), $subject);
|
||||||
|
$count = count($parts) - 1;
|
||||||
|
$subject = implode($replace, $parts);
|
||||||
|
} //end if
|
||||||
|
return $subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the field is unique
|
||||||
|
*
|
||||||
|
* @param string $table
|
||||||
|
* @param string $field
|
||||||
|
* @param mixed $value
|
||||||
|
* @param integer|null $id
|
||||||
|
* @param callable|null $query
|
||||||
|
* @return void
|
||||||
|
* @throws \Illuminate\Validation\ValidationException If the field is not unique.
|
||||||
|
*/
|
||||||
|
public static function assertFieldIsUnique(
|
||||||
|
string $table,
|
||||||
|
string $field,
|
||||||
|
mixed $value,
|
||||||
|
?int $id = null,
|
||||||
|
?callable $query = null
|
||||||
|
) {
|
||||||
|
if (!$query) {
|
||||||
|
Validator::make([$field => $value], [
|
||||||
|
$field => Rule::unique($table, $field)->ignore($id),
|
||||||
|
], [
|
||||||
|
$field . '.unique' => trans('La valeur :value pour le champ :attribute est déjà utilisé', [
|
||||||
|
'attribute' => $field,
|
||||||
|
'value' => $value
|
||||||
|
])
|
||||||
|
])->validate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Validator::make([$field => $value], [
|
||||||
|
$field => Rule::unique($table)->where($query)->ignore($id),
|
||||||
|
], [
|
||||||
|
$field . '.unique' => trans('La valeur pour le champ :attribute est déjà utilisé', [
|
||||||
|
'attribute' => $field
|
||||||
|
])
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that two arrays have the same content (1 level only)
|
||||||
|
*
|
||||||
|
* @param array $array1
|
||||||
|
* @param array $array2
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function arrayHaveSameContent(array $array1, array $array2): bool
|
||||||
|
{
|
||||||
|
return (array_diff($array1, $array2) == [] && array_diff($array2, $array1) == []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get validated pagination from request
|
||||||
|
*
|
||||||
|
* @param integer $default
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public static function getValidatedPaginate(int $default): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return \intval(Validator::make(
|
||||||
|
['pagination' => \request()->get('pagination')],
|
||||||
|
['pagination' => new Enum(ItemsPerPaginationEnum::class)]
|
||||||
|
)->validated()['pagination']);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
app/Models/Brand.php
Normal file
55
app/Models/Brand.php
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $filter
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property Promo[] $promos
|
||||||
|
* @property Promo[] $promo
|
||||||
|
* @property Product[] $products
|
||||||
|
*/
|
||||||
|
class Brand extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'filter',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||||
|
*/
|
||||||
|
public function promos()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany('App\Models\Promo', 'promo_brands');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function promo()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Promo');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function products()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Product');
|
||||||
|
}
|
||||||
|
}
|
||||||
80
app/Models/Ingredient.php
Normal file
80
app/Models/Ingredient.php
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Ingredients\OriginEnum;
|
||||||
|
use App\Enums\Ingredients\FamilyEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $user_id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $supplier
|
||||||
|
* @property enum $origin
|
||||||
|
* @property boolean $is_sample
|
||||||
|
* @property enum $family
|
||||||
|
* @property string $packing
|
||||||
|
* @property string $function
|
||||||
|
* @property string $observation
|
||||||
|
* @property string $picture
|
||||||
|
* @property string $url
|
||||||
|
* @property string $documents
|
||||||
|
* @property string $fair
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property string $deleted_at
|
||||||
|
* @property User $user
|
||||||
|
*/
|
||||||
|
class Ingredient extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'name',
|
||||||
|
'supplier',
|
||||||
|
'origin',
|
||||||
|
'is_sample',
|
||||||
|
'family',
|
||||||
|
'packing',
|
||||||
|
'function',
|
||||||
|
'observation',
|
||||||
|
'picture',
|
||||||
|
'url',
|
||||||
|
'documents',
|
||||||
|
'fair',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'origin' => OriginEnum::class,
|
||||||
|
'is_sample' => 'boolean',
|
||||||
|
'family' => FamilyEnum::class,
|
||||||
|
'packing' => 'json',
|
||||||
|
'function' => 'json',
|
||||||
|
'documents' => 'json',
|
||||||
|
'created_at' => 'datetime:Y-m-d',
|
||||||
|
'updated_at' => 'datetime:Y-m-d',
|
||||||
|
'deleted_at' => 'datetime:Y-m-d',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\User');
|
||||||
|
}
|
||||||
|
}
|
||||||
59
app/Models/Keyword.php
Normal file
59
app/Models/Keyword.php
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\KeywordCategoryEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property string $label
|
||||||
|
* @property \App\Enums\KeywordCategoryEnum $keyword_cat
|
||||||
|
* @property \Carbon\Carbon $created_at
|
||||||
|
* @property \Carbon\Carbon $updated_at
|
||||||
|
*
|
||||||
|
* * RELATIONSHIPS
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Product> $products
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Keyword> $keywordables
|
||||||
|
*/
|
||||||
|
class Keyword extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'label',
|
||||||
|
'keyword_cat',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'keyword_cat' => KeywordCategoryEnum::class
|
||||||
|
];
|
||||||
|
|
||||||
|
// * RELATIONSHIPS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function keywordables()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Keywordable::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MorphToMany products relation.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||||
|
*/
|
||||||
|
public function products()
|
||||||
|
{
|
||||||
|
return $this->morphToMany(Product::class, 'keywordable');
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/Models/Keywordable.php
Normal file
39
app/Models/Keywordable.php
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $keyword_id
|
||||||
|
* @property integer $keywordable_id
|
||||||
|
* @property string $keywordable_type
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property Keyword $keyword
|
||||||
|
*/
|
||||||
|
class Keywordable extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'keyword_id',
|
||||||
|
'keywordable_id',
|
||||||
|
'keywordable_type',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function keyword()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Keyword');
|
||||||
|
}
|
||||||
|
}
|
||||||
86
app/Models/Packaging.php
Normal file
86
app/Models/Packaging.php
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Packaging\OriginEnum;
|
||||||
|
use App\Enums\Packaging\WatchTypeEnum;
|
||||||
|
use App\Enums\Packaging\TypeEnum;
|
||||||
|
use App\Enums\Packaging\MaterialEnum;
|
||||||
|
use App\Enums\Packaging\BenefitEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $user_id
|
||||||
|
* @property boolean $watch_type
|
||||||
|
* @property string $supplier
|
||||||
|
* @property string $name
|
||||||
|
* @property string $product_description
|
||||||
|
* @property boolean $origin
|
||||||
|
* @property boolean $is_sample
|
||||||
|
* @property boolean $type_packaging
|
||||||
|
* @property boolean $material
|
||||||
|
* @property boolean $benefit
|
||||||
|
* @property string $observation
|
||||||
|
* @property string $picture
|
||||||
|
* @property string $url
|
||||||
|
* @property string $documents
|
||||||
|
* @property string $fair
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property string $deleted_at
|
||||||
|
* @property User $user
|
||||||
|
*/
|
||||||
|
class Packaging extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'watch_type',
|
||||||
|
'supplier',
|
||||||
|
'name',
|
||||||
|
'product_description',
|
||||||
|
'origin',
|
||||||
|
'is_sample',
|
||||||
|
'type_packaging',
|
||||||
|
'material',
|
||||||
|
'benefit',
|
||||||
|
'observation',
|
||||||
|
'picture',
|
||||||
|
'url',
|
||||||
|
'documents',
|
||||||
|
'fair',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'watch_type' => WatchTypeEnum::class,
|
||||||
|
'origin' => OriginEnum::class,
|
||||||
|
'is_sample' => 'boolean',
|
||||||
|
'type_packaging' => TypeEnum::class,
|
||||||
|
'material' => MaterialEnum::class,
|
||||||
|
'benefit' => BenefitEnum::class,
|
||||||
|
'picture' => 'json',
|
||||||
|
'documents' => 'json',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\User');
|
||||||
|
}
|
||||||
|
}
|
||||||
93
app/Models/Process.php
Normal file
93
app/Models/Process.php
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Process\WatchTypeEnum;
|
||||||
|
use App\Enums\Process\OriginEnum;
|
||||||
|
use App\Enums\Process\BenefitEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $user_id
|
||||||
|
* @property boolean $watch_type
|
||||||
|
* @property string $supplier
|
||||||
|
* @property string $name
|
||||||
|
* @property string $description
|
||||||
|
* @property boolean $origin
|
||||||
|
* @property boolean $is_test_machine
|
||||||
|
* @property boolean $is_quotation
|
||||||
|
* @property string $quotation_document
|
||||||
|
* @property boolean $profit
|
||||||
|
* @property string $observation
|
||||||
|
* @property string $picture
|
||||||
|
* @property string $documents
|
||||||
|
* @property string $url
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property string $deleted_at
|
||||||
|
* @property ProcessHasProcessType[] $processHasProcessTypes
|
||||||
|
* @property User $user
|
||||||
|
*/
|
||||||
|
class Process extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'watch_type',
|
||||||
|
'supplier',
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'origin',
|
||||||
|
'is_test_machine',
|
||||||
|
'is_quotation',
|
||||||
|
'quotation_document',
|
||||||
|
'profit',
|
||||||
|
'observation',
|
||||||
|
'picture',
|
||||||
|
'documents',
|
||||||
|
'url',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'watch_type' => WatchTypeEnum::class,
|
||||||
|
'origin' => OriginEnum::class,
|
||||||
|
'is_test_machine' => 'boolean',
|
||||||
|
'is_quotation' => 'boolean',
|
||||||
|
'profit' => BenefitEnum::class,
|
||||||
|
'picture' => 'json',
|
||||||
|
'documents' => 'json',
|
||||||
|
'created_at' => 'datetime:Y-m-d',
|
||||||
|
'updated_at' => 'datetime:Y-m-d',
|
||||||
|
'deleted_at' => 'datetime:Y-m-d',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function processHasProcessTypes()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\ProcessHasProcessType', 'process_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\User');
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Models/ProcessHasProcessType.php
Normal file
52
app/Models/ProcessHasProcessType.php
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $process_id
|
||||||
|
* @property integer $process_type_id
|
||||||
|
* @property string $value_enum
|
||||||
|
* @property ProcessType $processType
|
||||||
|
* @property Process $process
|
||||||
|
*/
|
||||||
|
class ProcessHasProcessType extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'process_id',
|
||||||
|
'process_type_id',
|
||||||
|
'value_enum'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'value_enum' => 'json'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function processType()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\ProcessType');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Process');
|
||||||
|
}
|
||||||
|
}
|
||||||
32
app/Models/ProcessType.php
Normal file
32
app/Models/ProcessType.php
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property ProcessHasProcessType[] $processHasProcessTypes
|
||||||
|
*/
|
||||||
|
class ProcessType extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function processHasProcessTypes()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\ProcessHasProcessType', 'process_type_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
452
app/Models/Product.php
Normal file
452
app/Models/Product.php
Normal file
|
|
@ -0,0 +1,452 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Products\CertificationEnum;
|
||||||
|
use App\Enums\Products\ClaimEnum;
|
||||||
|
use App\Enums\Products\DistributionNetworkEnum;
|
||||||
|
use App\Enums\Products\GeoAreaEnum;
|
||||||
|
use App\Enums\Products\OriginEnum;
|
||||||
|
use App\Enums\Products\RangeEnum;
|
||||||
|
use App\Enums\Products\RayEnum;
|
||||||
|
use App\Enums\Products\SourceEnum;
|
||||||
|
use App\Http\Resources\ProductResource;
|
||||||
|
use App\Lib\Helpers\FileStorageHelper;
|
||||||
|
use App\Lib\Helpers\ToolboxHelper;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: using migration, do not set nullable props without a real need.
|
||||||
|
*
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $user_id
|
||||||
|
* @property integer $brand_id
|
||||||
|
* @property string $name
|
||||||
|
* @property \Carbon\Carbon $seen_at
|
||||||
|
* @property \App\Enums\Products\SourceEnum $source
|
||||||
|
* @property string|null $fair
|
||||||
|
* @property string|null $shop
|
||||||
|
* @property string|null $catalogue
|
||||||
|
* @property string|null $gencod
|
||||||
|
* @property string|null $picture
|
||||||
|
* @property string $picture_alt
|
||||||
|
* @property string $picture_title
|
||||||
|
* @property array|null $docs
|
||||||
|
* @property string|null $url
|
||||||
|
* @property \App\Enums\Products\CertificationEnum|null $certification
|
||||||
|
* @property array<integer>|null $origins
|
||||||
|
* @property \Illuminate\Support\Collection<\App\Enums\Products\OriginEnum> $origins_enum
|
||||||
|
* @property array<integer>|null $claims
|
||||||
|
* @property \Illuminate\Support\Collection<\App\Enums\Products\OriginEnum> $claims_enum
|
||||||
|
* @property string|null $specified_claim
|
||||||
|
* @property \App\Enums\Products\DistributionNetworkEnum $distribution_network
|
||||||
|
* @property \App\Enums\Products\RayEnum $ray
|
||||||
|
* @property \App\Enums\Products\RangeEnum $product_range
|
||||||
|
* @property \App\Enums\Products\GeoAreaEnum $geo area
|
||||||
|
* @property integer|null $weight
|
||||||
|
* @property integer|null $pvc
|
||||||
|
* @property string|null $comment
|
||||||
|
* @property boolean $is_tasted
|
||||||
|
* @property integer|null $tasters_number
|
||||||
|
* @property \Carbon\Carbon|null $created_at
|
||||||
|
* @property \Carbon\Carbon|null $updated_at
|
||||||
|
* @property \Carbon\Carbon|null $deleted_at
|
||||||
|
*
|
||||||
|
* * RELATIONSHIPS
|
||||||
|
* @property-read \App\Models\Brand $brand
|
||||||
|
* @property-read \App\Models\User $user
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\ProductComment> $productComments
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Keyword> $productKeywords
|
||||||
|
*/
|
||||||
|
class Product extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'brand_id',
|
||||||
|
'name',
|
||||||
|
// ? FIXME: ?why is there brand here, column is not in DB.
|
||||||
|
'brand',
|
||||||
|
'seen_at',
|
||||||
|
'source',
|
||||||
|
'fair',
|
||||||
|
'shop',
|
||||||
|
'catalogue',
|
||||||
|
'gencod',
|
||||||
|
'picture',
|
||||||
|
'picture_alt',
|
||||||
|
'picture_title',
|
||||||
|
'docs',
|
||||||
|
'url',
|
||||||
|
'certification',
|
||||||
|
'origins',
|
||||||
|
'claims',
|
||||||
|
'specified_claim',
|
||||||
|
'distribution_network',
|
||||||
|
'ray',
|
||||||
|
'product_range',
|
||||||
|
'geo_area',
|
||||||
|
'weight',
|
||||||
|
'pvc',
|
||||||
|
'comment',
|
||||||
|
'is_tasted',
|
||||||
|
'tasters_number',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'source' => SourceEnum::class,
|
||||||
|
'docs' => 'json',
|
||||||
|
'certification' => CertificationEnum::class,
|
||||||
|
'origins' => 'json',
|
||||||
|
'claims' => 'json',
|
||||||
|
'distribution_network' => DistributionNetworkEnum::class,
|
||||||
|
'ray' => RayEnum::class,
|
||||||
|
'product_range' => RangeEnum::class,
|
||||||
|
'geo_area' => GeoAreaEnum::class,
|
||||||
|
'is_tasted' => 'boolean',
|
||||||
|
'seen_at' => 'datetime',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime',
|
||||||
|
'deleted_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
// * EVENTS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "booted" method of the model.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected static function booted(): void
|
||||||
|
{
|
||||||
|
static::creating(function (self $model) {
|
||||||
|
self::assertFieldIsUnique('name', $model->name);
|
||||||
|
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||||
|
self::updateSource($model);
|
||||||
|
// FIXME: lier le produit à l'utilisateur connecté lors de l'ajout du système de connexion.
|
||||||
|
$model->user_id = 1;
|
||||||
|
});
|
||||||
|
static::updating(function (self $model) {
|
||||||
|
self::deleteOldDocuments($model, true);
|
||||||
|
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||||
|
self::updateSource($model);
|
||||||
|
self::updateSpecifiedClaim($model);
|
||||||
|
});
|
||||||
|
static::updated(function (self $model) {
|
||||||
|
FileStorageHelper::removeOldFile($model, 'picture');
|
||||||
|
});
|
||||||
|
static::deleted(function (self $model) {
|
||||||
|
self::deleteOldDocuments($model);
|
||||||
|
FileStorageHelper::removeFile($model, 'picture');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// * METHODS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts using validation that the field is unique.
|
||||||
|
*
|
||||||
|
* @param string $field
|
||||||
|
* @param string $value
|
||||||
|
* @param integer|null $id
|
||||||
|
* @return void
|
||||||
|
* @throws \Illuminate\Validation\ValidationException If field already exists.
|
||||||
|
*/
|
||||||
|
private static function assertFieldIsUnique(string $field, string $value, ?int $id = null)
|
||||||
|
{
|
||||||
|
$table = (new self())->getTable();
|
||||||
|
ToolboxHelper::assertFieldIsUnique($table, $field, $value, $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update data specified claim.
|
||||||
|
*
|
||||||
|
* @param \App\Models\Product $model
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function updateSpecifiedClaim(Product $model)
|
||||||
|
{
|
||||||
|
$check = false;
|
||||||
|
foreach ($model->claims as $claimValue) {
|
||||||
|
if (!$check) {
|
||||||
|
$check = (intval($claimValue) === \App\Enums\Products\ClaimEnum::others->value) ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$model->specified_claim = ($check) ? $model->specified_claim : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update data source.
|
||||||
|
*
|
||||||
|
* @param self $model
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function updateSource(self $model)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
$model->source === \App\Enums\Products\SourceEnum::showConsumer ||
|
||||||
|
$model->source === \App\Enums\Products\SourceEnum::showCustomer ||
|
||||||
|
$model->source === \App\Enums\Products\SourceEnum::showTrade
|
||||||
|
) {
|
||||||
|
$model->shop = null;
|
||||||
|
$model->catalogue = null;
|
||||||
|
} elseif ($model->source === \App\Enums\Products\SourceEnum::magazin) {
|
||||||
|
$model->fair = null;
|
||||||
|
$model->catalogue = null;
|
||||||
|
} elseif ($model->source === \App\Enums\Products\SourceEnum::catalogArgumentary) {
|
||||||
|
$model->fair = null;
|
||||||
|
$model->shop = null;
|
||||||
|
} else {
|
||||||
|
$model->fair = null;
|
||||||
|
$model->shop = null;
|
||||||
|
$model->catalogue = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete old documents.
|
||||||
|
*
|
||||||
|
* @param self $model
|
||||||
|
* @param boolean $onlyIfUpdated
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function deleteOldDocuments(self $model, bool $onlyIfUpdated = false)
|
||||||
|
{
|
||||||
|
$original = \collect($model->getOriginal('docs'))->map(fn ($document) => strval($document));
|
||||||
|
$new = \collect($model->docs)->map(fn ($document) => strval($document))->flip();
|
||||||
|
foreach ($original as $document) {
|
||||||
|
// * Ignore if document is to keep.
|
||||||
|
if ($onlyIfUpdated and $new->has($document)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$originalPath = \ltrim(\urldecode($document), '/');
|
||||||
|
if (\strpos($originalPath, 'storage') !== 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
|
||||||
|
if (Storage::disk('public')->exists($originalPath)) {
|
||||||
|
Storage::disk('public')->delete($originalPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate product sheet PDF.
|
||||||
|
*
|
||||||
|
* @param self $model
|
||||||
|
* @param string $title
|
||||||
|
* @return \Mccarlosen\LaravelMpdf\LaravelMpdf
|
||||||
|
*/
|
||||||
|
public static function generateProductPdf(self $model, string $title): LaravelMpdf
|
||||||
|
{
|
||||||
|
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf */
|
||||||
|
$mpdf = app('laravel-mpdf');
|
||||||
|
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf */
|
||||||
|
$pdf = $mpdf->loadView(
|
||||||
|
'documents.product',
|
||||||
|
// * Dirty convert to object.
|
||||||
|
[
|
||||||
|
'title' => $title,
|
||||||
|
'product' => \json_decode(\json_encode(new ProductResource($model)))
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'mode' => 'utf-8',
|
||||||
|
'format' => 'A4',
|
||||||
|
'default_font_size' => '12',
|
||||||
|
'default_font' => 'sans-serif',
|
||||||
|
'mirrorMargins' => true,
|
||||||
|
'margin_left' => 10,
|
||||||
|
'margin_right' => 10,
|
||||||
|
'margin_top' => 10,
|
||||||
|
'margin_bottom' => 10,
|
||||||
|
'margin_header' => 10,
|
||||||
|
'margin_footer' => 10,
|
||||||
|
'margin_top' => 10,
|
||||||
|
'orientation' => 'L',
|
||||||
|
'title' => $title,
|
||||||
|
'author' => \config('app.name', 'Startcoq'),
|
||||||
|
'watermark' => '',
|
||||||
|
'show_watermark' => false,
|
||||||
|
'watermark_font' => 'sans-serif',
|
||||||
|
'display_mode' => 'fullpage',
|
||||||
|
'watermark_text_alpha' => 0.1,
|
||||||
|
'custom_font_dir' => '',
|
||||||
|
'custom_font_data' => [],
|
||||||
|
'auto_language_detection' => false,
|
||||||
|
'temp_dir' => rtrim(
|
||||||
|
ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(),
|
||||||
|
DIRECTORY_SEPARATOR
|
||||||
|
),
|
||||||
|
'pdfa' => false,
|
||||||
|
'pdfaauto' => false,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a pdf with multiple products.
|
||||||
|
*
|
||||||
|
* @param array<integer> $printMultiProduct
|
||||||
|
* @param string $title
|
||||||
|
* @return \Mccarlosen\LaravelMpdf\LaravelMpdf
|
||||||
|
*/
|
||||||
|
public static function generateMultipleProductPdf(array $printMultiProduct, string $title)
|
||||||
|
{
|
||||||
|
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf|null */
|
||||||
|
$pdf = null;
|
||||||
|
// * Loop all Model ids.
|
||||||
|
foreach ($printMultiProduct as $productId) {
|
||||||
|
/** @var \App\Models\Product */
|
||||||
|
$product = Product::query()->where('id', $productId)->firstOrFail();
|
||||||
|
// * If not yet defined, set the first page.
|
||||||
|
if (is_null($pdf)) {
|
||||||
|
$pdf = Product::generateProductPdf($product, $title);
|
||||||
|
} else {
|
||||||
|
// * Add another page and add HTML from view to this.
|
||||||
|
$pdf->getMpdf()->AddPage();
|
||||||
|
$pdf->getMpdf()->WriteHTML((string)view(
|
||||||
|
'documents.product-body',
|
||||||
|
['product' => (object)(new ProductResource($product))->toArray()],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch and stream export file.
|
||||||
|
*
|
||||||
|
* @param string $filepath
|
||||||
|
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
||||||
|
* @throws \Error If file storage config is wrong.
|
||||||
|
*/
|
||||||
|
public static function downloadPrivateExportFile(string $filepath): StreamedResponse
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||||
|
$disk = Storage::disk('export');
|
||||||
|
|
||||||
|
if (!($disk instanceof \Illuminate\Filesystem\FilesystemAdapter)) {
|
||||||
|
throw new \Error('Le disque de stockage doit être un système de fichiers local');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$disk->exists($filepath)) {
|
||||||
|
\abort(400, trans('Le fichier demandé est périmé et n\'existe plus'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return \response()->stream(function () use ($disk, $filepath) {
|
||||||
|
echo $disk->get($filepath);
|
||||||
|
}, 200, [
|
||||||
|
'Cache-Control' => 'public, must-revalidate, max-age=0',
|
||||||
|
'Content-Description' => 'File Transfer',
|
||||||
|
'Content-Type' => $disk->mimeType($filepath),
|
||||||
|
'Expires' => 'Sat, 26 Jul 1997 05:00:00 GMT',
|
||||||
|
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT'
|
||||||
|
])->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
// * GETTERS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get origins_enum attribute
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Support\Collection<\App\Enums\Ingredients\OriginEnum>
|
||||||
|
*/
|
||||||
|
public function getOriginsEnumAttribute(): Collection
|
||||||
|
{
|
||||||
|
return \collect($this->getAttribute('origins'))->filter()
|
||||||
|
->map(fn (int $originEnumValue) => OriginEnum::make($originEnumValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set origins_enum attribute
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setOriginsEnumAttribute(mixed $value): void
|
||||||
|
{
|
||||||
|
$this->setAttribute('origins', \collect($value)->filter()
|
||||||
|
->map(fn ($originEnumValue) => OriginEnum::make($originEnumValue)->value())
|
||||||
|
->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get claims_enum attribute
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Support\Collection<\App\Enums\Ingredients\ClaimEnum>
|
||||||
|
*/
|
||||||
|
public function getClaimsEnumAttribute(): Collection
|
||||||
|
{
|
||||||
|
return \collect($this->getAttribute('claims'))->filter()
|
||||||
|
->map(fn (int $originEnumValue) => ClaimEnum::make($originEnumValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set claims_enum attribute
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClaimsEnumAttribute(mixed $value): void
|
||||||
|
{
|
||||||
|
$this->setAttribute('claims', \collect($value)->filter()
|
||||||
|
->map(fn ($claimEnumValue) => OriginEnum::make($claimEnumValue)->value())
|
||||||
|
->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
// * RELATIONSHIPS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function productComments()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ProductComment::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function brand()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Brand::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MorphToMany keywords relation.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||||
|
*/
|
||||||
|
public function productKeywords()
|
||||||
|
{
|
||||||
|
return $this->morphToMany(Keyword::class, 'keywordable');
|
||||||
|
}
|
||||||
|
}
|
||||||
59
app/Models/ProductComment.php
Normal file
59
app/Models/ProductComment.php
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $product_id
|
||||||
|
* @property string $evaluation
|
||||||
|
* @property string|null $aspect
|
||||||
|
* @property string|null $taste
|
||||||
|
* @property string|null $odor
|
||||||
|
* @property string|null $texture
|
||||||
|
* @property \Carbon\Carbon $created_at
|
||||||
|
* @property \Carbon\Carbon $updated_at
|
||||||
|
*
|
||||||
|
* * RELATIONSHIPS
|
||||||
|
* @property-read \App\Models\Product $product
|
||||||
|
*/
|
||||||
|
class ProductComment extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'product_id',
|
||||||
|
'evaluation',
|
||||||
|
'aspect',
|
||||||
|
'taste',
|
||||||
|
'odor',
|
||||||
|
'texture',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
// * RELATIONSHIPS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function product()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Product::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
123
app/Models/Promo.php
Normal file
123
app/Models/Promo.php
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Promotions\SourceEnum;
|
||||||
|
use App\Enums\Promotions\TargetEnum;
|
||||||
|
use App\Enums\Promotions\AngleEnum;
|
||||||
|
use App\Enums\Promotions\EventEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $user_id
|
||||||
|
* @property integer $promo_type_id
|
||||||
|
* @property integer $promo_distribution_network_id
|
||||||
|
* @property integer $brand_id
|
||||||
|
* @property string $date
|
||||||
|
* @property boolean $source
|
||||||
|
* @property string $shop_name
|
||||||
|
* @property string $shop_city
|
||||||
|
* @property string $sector_chief
|
||||||
|
* @property string $name
|
||||||
|
* @property string $target
|
||||||
|
* @property string $angle
|
||||||
|
* @property string $event
|
||||||
|
* @property string $url
|
||||||
|
* @property string $press
|
||||||
|
* @property string $fair
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property string $deleted_at
|
||||||
|
* @property Brand[] $brands
|
||||||
|
* @property PromoType $promoType
|
||||||
|
* @property PromoDistributionNetwork $promoDistributionNetwork
|
||||||
|
* @property User $user
|
||||||
|
* @property Brand $brand
|
||||||
|
*/
|
||||||
|
class Promo extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'promo_type_id',
|
||||||
|
'promo_distribution_network_id',
|
||||||
|
'brand_id',
|
||||||
|
'date',
|
||||||
|
'source',
|
||||||
|
'shop_name',
|
||||||
|
'shop_city',
|
||||||
|
'sector_chief',
|
||||||
|
'name',
|
||||||
|
'target',
|
||||||
|
'angle',
|
||||||
|
'event',
|
||||||
|
'url',
|
||||||
|
'press',
|
||||||
|
'fair',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'source' => SourceEnum::class,
|
||||||
|
'target' => TargetEnum::class,
|
||||||
|
'angle' => AngleEnum::class,
|
||||||
|
'event' => EventEnum::class,
|
||||||
|
'date' => 'datetime:Y-m-d',
|
||||||
|
'created_at' => 'datetime:Y-m-d',
|
||||||
|
'updated_at' => 'datetime:Y-m-d',
|
||||||
|
'deleted_at' => 'datetime:Y-m-d',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||||
|
*/
|
||||||
|
public function brands()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany('App\Models\Brand', 'promo_brands');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function brand()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Brand');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function promoType()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\PromoType');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function promoDistributionNetwork()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\PromoDistributionNetwork');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\User');
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/Models/PromoDistributionNetwork.php
Normal file
47
app/Models/PromoDistributionNetwork.php
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Promotions\DistributionNetworkEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property boolean $name
|
||||||
|
* @property string $label
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property Promo[] $promos
|
||||||
|
*/
|
||||||
|
class PromoDistributionNetwork extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'label',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'name' => DistributionNetworkEnum::class
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function promos()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Promo');
|
||||||
|
}
|
||||||
|
}
|
||||||
54
app/Models/PromoType.php
Normal file
54
app/Models/PromoType.php
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Promotions\TypeEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property boolean $name
|
||||||
|
* @property string $label
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property Promo[] $promos
|
||||||
|
*/
|
||||||
|
class PromoType extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the IDs are auto-incrementing.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $incrementing = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'value',
|
||||||
|
'label',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'value' => TypeEnum::class
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function promos()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Promo');
|
||||||
|
}
|
||||||
|
}
|
||||||
70
app/Models/Survey.php
Normal file
70
app/Models/Survey.php
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Surveys\CustomerEnum;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property integer $id
|
||||||
|
* @property integer $user_id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $author
|
||||||
|
* @property string $comment
|
||||||
|
* @property string $date
|
||||||
|
* @property string $documents
|
||||||
|
* @property boolean $is_distributor
|
||||||
|
* @property boolean $is_customer
|
||||||
|
* @property boolean $type
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
* @property string $deleted_at
|
||||||
|
* @property User $user
|
||||||
|
*/
|
||||||
|
class Survey extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'name',
|
||||||
|
'author',
|
||||||
|
'comment',
|
||||||
|
'date',
|
||||||
|
'documents',
|
||||||
|
'is_distributor',
|
||||||
|
'is_customer',
|
||||||
|
'type',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'date' => 'datetime:Y-m-d',
|
||||||
|
'documents' => 'json',
|
||||||
|
'is_distributor' => 'boolean',
|
||||||
|
'is_customer' => 'boolean',
|
||||||
|
'type' => CustomerEnum::class,
|
||||||
|
'created_at' => 'datetime:Y-m-d',
|
||||||
|
'updated_at' => 'datetime:Y-m-d',
|
||||||
|
'deleted_at' => 'datetime:Y-m-d',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\User');
|
||||||
|
}
|
||||||
|
}
|
||||||
43
app/Models/User.php
Normal file
43
app/Models/User.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
|
class User extends Authenticatable
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use Notifiable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be hidden for serialization.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $hidden = [
|
||||||
|
'password',
|
||||||
|
'remember_token',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'email_verified_at' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
42
app/Providers/AppServiceProvider.php
Normal file
42
app/Providers/AppServiceProvider.php
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\URL;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class AppServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
// * LOCAL HTTPS FIX
|
||||||
|
URL::forceScheme('https');
|
||||||
|
|
||||||
|
// * HA PROXY FIX
|
||||||
|
App::singleton('clientIp', function () {
|
||||||
|
if (
|
||||||
|
config('app.env') === 'local'
|
||||||
|
) {
|
||||||
|
return request()->getClientIp();
|
||||||
|
} else {
|
||||||
|
return request()->server('HTTP_X_FORWARDED_FOR') ??
|
||||||
|
request()->getClientIp();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// * LOCAL FORCE eg: for Carbon
|
||||||
|
setlocale(LC_ALL, \sprintf(
|
||||||
|
'%s_%s.UTF-8',
|
||||||
|
config('app.locale'),
|
||||||
|
\strtoupper(config('app.locale'))
|
||||||
|
));
|
||||||
|
Carbon::setLocale(config('app.locale'));
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Providers/AuthServiceProvider.php
Normal file
24
app/Providers/AuthServiceProvider.php
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
|
class AuthServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The model to policy mappings for the application.
|
||||||
|
*
|
||||||
|
* @var array<class-string, class-string>
|
||||||
|
*/
|
||||||
|
protected $policies = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register any authentication / authorization services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Providers/EventServiceProvider.php
Normal file
38
app/Providers/EventServiceProvider.php
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\Registered;
|
||||||
|
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||||
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
|
class EventServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The event to listener mappings for the application.
|
||||||
|
*
|
||||||
|
* @var array<class-string, array<int, class-string>>
|
||||||
|
*/
|
||||||
|
protected $listen = [
|
||||||
|
Registered::class => [
|
||||||
|
SendEmailVerificationNotification::class,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register any events for your application.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if events and listeners should be automatically discovered.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function shouldDiscoverEvents(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
93
app/Providers/RouteServiceProvider.php
Normal file
93
app/Providers/RouteServiceProvider.php
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Cache\RateLimiting\Limit;
|
||||||
|
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
class RouteServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 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 = '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define your route model bindings, pattern filters, etc.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
$this->configureRateLimiting();
|
||||||
|
|
||||||
|
$this->cspReportRoute();
|
||||||
|
|
||||||
|
$this->routes(function () {
|
||||||
|
Route::middleware('web')
|
||||||
|
->namespace($this->namespace)
|
||||||
|
->group(base_path('routes/web.php'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the rate limiters for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function configureRateLimiting()
|
||||||
|
{
|
||||||
|
RateLimiter::for('api', function (Request $request) {
|
||||||
|
return Limit::perMinute(150)->by(optional($request->user())->id ?: app('clientIp'));
|
||||||
|
});
|
||||||
|
RateLimiter::for('web', function (Request $request) {
|
||||||
|
return Limit::perMinute(150)->by(optional($request->user())->id ?: app('clientIp'));
|
||||||
|
});
|
||||||
|
RateLimiter::for('credentials', function (Request $request) {
|
||||||
|
return Limit::perMinute(30)->by(optional($request->user())->id ?: $request->ip());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * Register CSP report URI
|
||||||
|
*
|
||||||
|
* Put this function inside RouteServiceProvider,
|
||||||
|
* and call it in RouteServiceProvider::boot
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function cspReportRoute()
|
||||||
|
{
|
||||||
|
// * CSP REPORT URI, Please add /csp-report to VerifyCsrfToken $except middleware
|
||||||
|
\Illuminate\Support\Facades\Route::post('/csp-report', function () {
|
||||||
|
$isCspRequest = request()->header('Content-Type') === 'application/csp-report';
|
||||||
|
if (!$isCspRequest or !request()->json('csp-report') or !is_array(request()->json('csp-report'))) {
|
||||||
|
abort(401);
|
||||||
|
}
|
||||||
|
// * Flatten if needed
|
||||||
|
$cspReport = collect(request()->json('csp-report'))
|
||||||
|
->flatMap(function ($v, $k) {
|
||||||
|
return [$k => is_array($v) ? collect($v)->flatten()->implode(', ') : $v];
|
||||||
|
})->all();
|
||||||
|
// * Filter array keys
|
||||||
|
$cspReport = collect(array_intersect_key($cspReport, [
|
||||||
|
'blocked-uri' => '', 'document-uri' => '', 'original-policy' => '',
|
||||||
|
'referrer' => '', 'violated-directive' => ''
|
||||||
|
]));
|
||||||
|
\Illuminate\Support\Facades\Log::warning(sprintf(
|
||||||
|
"CSP REPORT for %s : \n %s",
|
||||||
|
$cspReport->get('document-uri'),
|
||||||
|
$cspReport->implode("\n")
|
||||||
|
));
|
||||||
|
})->middleware('throttle:5,2')
|
||||||
|
->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class)
|
||||||
|
->name('cspReportUri');
|
||||||
|
}
|
||||||
|
}
|
||||||
78
app/Providers/TranslationServiceProvider.php
Normal file
78
app/Providers/TranslationServiceProvider.php
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Symfony\Component\Finder\SplFileInfo;
|
||||||
|
|
||||||
|
class TranslationServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap the application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
foreach ($this->collectLocalesStrings() as $locale) {
|
||||||
|
// * Suported locales
|
||||||
|
Cache::rememberForever(sprintf('translations.%s', $locale), function () use ($locale) {
|
||||||
|
$translations = [
|
||||||
|
'php' => $this->phpTranslations($locale),
|
||||||
|
'json' => $this->jsonTranslations($locale),
|
||||||
|
];
|
||||||
|
return $translations;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather provided langs checking from files
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function collectLocalesStrings(): Collection
|
||||||
|
{
|
||||||
|
return collect(File::allFiles(resource_path('lang/')))->flatMap(function (SplFileInfo $file) {
|
||||||
|
if ($file->getRelativePath() and \strpos($file->getRelativePath(), 'vendor') !== 0) {
|
||||||
|
return [$file->getRelativePath() => ''];
|
||||||
|
}
|
||||||
|
})->keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather all php translations
|
||||||
|
*
|
||||||
|
* @param string $locale
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function phpTranslations(string $locale): array
|
||||||
|
{
|
||||||
|
$path = resource_path("lang/$locale");
|
||||||
|
|
||||||
|
return collect(File::allFiles($path))->flatMap(function ($file) use ($locale) {
|
||||||
|
$translation = $file->getBasename('.php');
|
||||||
|
return [$translation => trans($translation, [], $locale)];
|
||||||
|
})->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather json translations
|
||||||
|
*
|
||||||
|
* @param string $locale
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function jsonTranslations(string $locale): array
|
||||||
|
{
|
||||||
|
$path = resource_path("lang/$locale.json");
|
||||||
|
|
||||||
|
if (is_string($path) && is_readable($path)) {
|
||||||
|
return json_decode(file_get_contents($path), true) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Providers/ViewServiceProvider.php
Normal file
19
app/Providers/ViewServiceProvider.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Pagination\Paginator;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class ViewServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
Paginator::defaultview('modules.pagination');
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Traits/Controllers/HasDocuments.php
Normal file
26
app/Traits/Controllers/HasDocuments.php
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits\Controllers;
|
||||||
|
|
||||||
|
use App\Lib\Helpers\FileStorageHelper;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
trait HasDocuments
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Save Model Images
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Illuminate\Database\Eloquent\Model $model
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function storeDocuments(Request $request, Model $model): void
|
||||||
|
{
|
||||||
|
$model->docs = [];
|
||||||
|
$model->docs = collect($request->docs)
|
||||||
|
->map(function ($document) use ($model) {
|
||||||
|
return FileStorageHelper::storeFile($model, $document);
|
||||||
|
})->all();
|
||||||
|
}
|
||||||
|
}
|
||||||
229
app/Traits/Enums/BaseEnum.php
Normal file
229
app/Traits/Enums/BaseEnum.php
Normal file
|
|
@ -0,0 +1,229 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits\Enums;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jérémy Munsch <jeremy.munsch@ldc.fr>
|
||||||
|
*/
|
||||||
|
trait BaseEnum
|
||||||
|
{
|
||||||
|
// * GENERIC METHODS
|
||||||
|
/**
|
||||||
|
* Get enum value
|
||||||
|
*
|
||||||
|
* @return string|integer
|
||||||
|
*/
|
||||||
|
public function value(): string|int
|
||||||
|
{
|
||||||
|
return self::toValues()[$this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get enum label
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return self::toLabels()[$this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
// * STATIC FETCH METHODS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get enum labels
|
||||||
|
*
|
||||||
|
* @return array<string>
|
||||||
|
*/
|
||||||
|
public static function toLabels(): array
|
||||||
|
{
|
||||||
|
if (empty(self::getCache('labels'))) {
|
||||||
|
$labels = self::getLabelsConstant();
|
||||||
|
self::setCache('labels', \collect(self::cases())
|
||||||
|
->mapWithKeys(function ($enum) use ($labels) {
|
||||||
|
if (!\is_null($labels) and !isset($labels[$enum->name])) {
|
||||||
|
throw new \Error('Missing definition label ' . self::class . " for {$enum->name}");
|
||||||
|
}
|
||||||
|
return [$enum->name => \trans(
|
||||||
|
!\is_null($labels) ? $labels[$enum->name] : Str::ucfirst($enum->name)
|
||||||
|
)];
|
||||||
|
})->all());
|
||||||
|
}
|
||||||
|
return self::getCache('labels');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get enum values
|
||||||
|
*
|
||||||
|
* @return array<integer|string>
|
||||||
|
*/
|
||||||
|
public static function toValues(): array
|
||||||
|
{
|
||||||
|
if (empty(self::getCache('values'))) {
|
||||||
|
self::setCache('values', \collect(self::cases())
|
||||||
|
->mapWithKeys(fn ($enum) => [$enum->name => $enum->value])->all());
|
||||||
|
}
|
||||||
|
return self::getCache('values');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get enums
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function toArray(): array
|
||||||
|
{
|
||||||
|
if (empty(self::getCache('enums'))) {
|
||||||
|
$definitions = self::getCustomDefinitions();
|
||||||
|
self::setCache('enums', \collect(self::cases())
|
||||||
|
->mapWithKeys(function ($enum) use ($definitions) {
|
||||||
|
$baseArray = [
|
||||||
|
'name' => $enum->name,
|
||||||
|
'label' => $enum->label(),
|
||||||
|
'value' => $enum->value,
|
||||||
|
];
|
||||||
|
foreach ($definitions as $index => $elements) {
|
||||||
|
$index = Str::lower(Str::singular($index));
|
||||||
|
if (!isset($elements[$enum->name])) {
|
||||||
|
throw new \Error("Missing definition {$index} " . self::class . " for {$enum->name}");
|
||||||
|
}
|
||||||
|
$baseArray[$index] = $elements[$enum->name];
|
||||||
|
}
|
||||||
|
return [$enum->name => (object)$baseArray];
|
||||||
|
})->all());
|
||||||
|
}
|
||||||
|
return self::getCache('enums');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch enum using value
|
||||||
|
*
|
||||||
|
* @param \App\Traits\Enums\BaseEnum|integer|string $value
|
||||||
|
* @return \App\Traits\Enums\BaseEnum|null
|
||||||
|
*/
|
||||||
|
public static function make(self|int|string $value): self|null
|
||||||
|
{
|
||||||
|
return !\is_object($value) ?
|
||||||
|
\collect(self::cases())->keyBy('value')->get($value) : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if 2 enum are equals
|
||||||
|
*
|
||||||
|
* @param object ...$others
|
||||||
|
* @return boolean
|
||||||
|
* @throws \Error If provided element are not enums taht extends BaseEnum.
|
||||||
|
*/
|
||||||
|
public function equals(object ...$others): bool
|
||||||
|
{
|
||||||
|
foreach ($others as $other) {
|
||||||
|
if (!\in_array(BaseEnum::class, \class_uses_recursive($other))) {
|
||||||
|
throw new \Error(__METHOD__ .
|
||||||
|
' requires $enum to use ' . BaseEnum::class);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
get_class($this) === get_class($other)
|
||||||
|
&& $this->value === $other->value
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * CACHE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cache array
|
||||||
|
*
|
||||||
|
* @param string $index
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function getCache(string $index): array
|
||||||
|
{
|
||||||
|
self::initCache();
|
||||||
|
if (!isset($GLOBALS[self::class]['props'][$index])) {
|
||||||
|
$GLOBALS[self::class]['props'][$index] = [];
|
||||||
|
}
|
||||||
|
return $GLOBALS[self::class]['props'][$index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cache array
|
||||||
|
*
|
||||||
|
* @param string $index
|
||||||
|
* @param array $items
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function setCache(string $index, array $items): void
|
||||||
|
{
|
||||||
|
self::initCache();
|
||||||
|
if (!isset($GLOBALS[self::class]['props'][$index])) {
|
||||||
|
$GLOBALS[self::class]['props'][$index] = [];
|
||||||
|
}
|
||||||
|
$GLOBALS[self::class]['props'][$index] = $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init cache if needed
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function initCache(): void
|
||||||
|
{
|
||||||
|
if (!isset($GLOBALS[self::class])) {
|
||||||
|
$GLOBALS[self::class] = [
|
||||||
|
'props' => [
|
||||||
|
'enums' => [],
|
||||||
|
'values' => [],
|
||||||
|
'labels' => []
|
||||||
|
],
|
||||||
|
'customProps' => null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// * PRIVATE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the LABELS constant if exists
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
private static function getLabelsConstant(): array|null
|
||||||
|
{
|
||||||
|
$class_name = self::class;
|
||||||
|
try {
|
||||||
|
$constant_reflex = new \ReflectionClassConstant($class_name, 'LABELS');
|
||||||
|
return $constant_reflex->getValue();
|
||||||
|
} catch (\ReflectionException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get custom constants
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function getCustomDefinitions(): array
|
||||||
|
{
|
||||||
|
// ? Has custom props in cache ?
|
||||||
|
if (\is_null($GLOBALS[self::class]['customProps'])) {
|
||||||
|
$names = \collect(self::cases())->keyBy('name');
|
||||||
|
|
||||||
|
$GLOBALS[self::class]['customProps'] = \collect((new \ReflectionClass(self::class))->getConstants())
|
||||||
|
->filter(function (mixed $constant, string $key) use ($names) {
|
||||||
|
if ($key === 'LABELS' or !\is_array($constant)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return \collect($constant)->keys()
|
||||||
|
->filter(fn (string $name) => $names->has($name))->count();
|
||||||
|
})->all();
|
||||||
|
}
|
||||||
|
return $GLOBALS[self::class]['customProps'];
|
||||||
|
}
|
||||||
|
}
|
||||||
112
app/Traits/Requests/HasDocumentAndPictureList.php
Normal file
112
app/Traits/Requests/HasDocumentAndPictureList.php
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
trait HasDocumentAndPictureList
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Autorised mimtypes
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $autorisedMimTypes = [
|
||||||
|
'application/msword',
|
||||||
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/gif',
|
||||||
|
'application/pdf',
|
||||||
|
'application/vnd.ms-powerpoint',
|
||||||
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
'application/vnd.ms-excel',
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'text/csv',
|
||||||
|
'text/plain',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Images rules
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function documentsRules(
|
||||||
|
string $name = 'docs',
|
||||||
|
): array {
|
||||||
|
return [
|
||||||
|
"{$name}" => 'present|array',
|
||||||
|
"{$name}.*" => [
|
||||||
|
'required',
|
||||||
|
function (string $attribute, $value, callable $fail) {
|
||||||
|
return $this->validateDocument($attribute, $value, $fail);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate picture.
|
||||||
|
*
|
||||||
|
* @param string $attribute
|
||||||
|
* @param mixed $value
|
||||||
|
* @param callback $fail
|
||||||
|
* @return void
|
||||||
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||||
|
*/
|
||||||
|
private function validateDocument(string $attribute, mixed $value, callable $fail)
|
||||||
|
{
|
||||||
|
// phpcs:enable
|
||||||
|
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
||||||
|
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!\in_array($this->getUploadedFileMimeType($value, $useStorage), $this->autorisedMimTypes)) {
|
||||||
|
$fail(trans(':attribute doit être un document de type :mimetypes', [
|
||||||
|
'mimetypes' => Str::of($this->autorisedMimTypes)->implode(' ou ')
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
$maxSize = 6 * 1024 * 1024;
|
||||||
|
if (File::size($value) > $maxSize) {
|
||||||
|
$fail(trans(':attribute doit être inférieur à :size Mo', ['size' => $maxSize / (1024 * 1024)]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges docs fields with request data.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function mergeDocuments(string $name = 'docs'): void
|
||||||
|
{
|
||||||
|
$documents = $this->{$name};
|
||||||
|
$this->merge([$name => $this->{$name} ?? []]);
|
||||||
|
$this->merge(["{$name}Validate" => []]);
|
||||||
|
if (is_array($documents)) {
|
||||||
|
foreach ($documents as $key => $documentPath) {
|
||||||
|
// ! Empty document.
|
||||||
|
if ($documentPath === 'false') {
|
||||||
|
// * Empty document and exit
|
||||||
|
$this->merge([$name => []]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$decodedPath = \urldecode($documentPath);
|
||||||
|
$this->merge([
|
||||||
|
"{$name}Validate" => array_merge(
|
||||||
|
$this->{"{$name}Validate"},
|
||||||
|
[\public_path(ltrim($decodedPath, '/'))]
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
$changedDocument = $this->{$name};
|
||||||
|
$changedDocument[$key] = ltrim($decodedPath, '/');
|
||||||
|
$this->merge([
|
||||||
|
$name => $changedDocument
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} //end if
|
||||||
|
}
|
||||||
|
}
|
||||||
261
app/Traits/Requests/HasPicture.php
Normal file
261
app/Traits/Requests/HasPicture.php
Normal file
|
|
@ -0,0 +1,261 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
trait HasPicture
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Minimum width
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $minWith = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum width
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $maxWith = 3840;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum height
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $minHeight = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum height
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $maxHeight = 2160;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image rules
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param boolean $required
|
||||||
|
* @param integer|null $minWith
|
||||||
|
* @param integer|null $minHeight
|
||||||
|
* @param integer|null $maxWith
|
||||||
|
* @param integer|null $maxHeight
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function pictureRules(
|
||||||
|
string $name = 'picture',
|
||||||
|
bool $required = true,
|
||||||
|
?int $minWith = null,
|
||||||
|
?int $minHeight = null,
|
||||||
|
?int $maxWith = null,
|
||||||
|
?int $maxHeight = null
|
||||||
|
): array {
|
||||||
|
$sizes = (object)[
|
||||||
|
'minWith' => $minWith ?? $this->minWith,
|
||||||
|
'minHeight' => $minHeight ?? $this->minHeight,
|
||||||
|
'maxWith' => $maxWith ?? $this->maxWith,
|
||||||
|
'maxHeight' => $maxHeight ?? $this->maxHeight
|
||||||
|
];
|
||||||
|
return [
|
||||||
|
$name => [
|
||||||
|
$required ? 'required' : 'nullable',
|
||||||
|
function (string $attribute, $value, callable $fail) use ($sizes) {
|
||||||
|
return $this->validatePicture($attribute, $value, $fail, $sizes);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Images rules
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param boolean $required
|
||||||
|
* @param integer|null $limitMin
|
||||||
|
* @param integer|null $limitMax
|
||||||
|
* @param integer|null $minWith
|
||||||
|
* @param integer|null $minHeight
|
||||||
|
* @param integer|null $maxWith
|
||||||
|
* @param integer|null $maxHeight
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function picturesRules(
|
||||||
|
string $name = 'pictures',
|
||||||
|
?bool $required = null,
|
||||||
|
?int $limitMin = null,
|
||||||
|
?int $limitMax = null,
|
||||||
|
?int $minWith = null,
|
||||||
|
?int $minHeight = null,
|
||||||
|
?int $maxWith = null,
|
||||||
|
?int $maxHeight = null
|
||||||
|
): array {
|
||||||
|
$sizes = (object)[
|
||||||
|
'required' => $required ?? $this->required,
|
||||||
|
'limitMin' => $limitMin ?? $this->limitMin,
|
||||||
|
'limitMax' => $limitMax ?? $this->limitMax,
|
||||||
|
'minWith' => $minWith ?? $this->minWith,
|
||||||
|
'minHeight' => $minHeight ?? $this->minHeight,
|
||||||
|
'maxWith' => $maxWith ?? $this->maxWith,
|
||||||
|
'maxHeight' => $maxHeight ?? $this->maxHeight
|
||||||
|
];
|
||||||
|
return [
|
||||||
|
"{$name}" => ($required ? 'required' : 'nullable') . "|array|between:$limitMin,$limitMax",
|
||||||
|
"{$name}.*" => [
|
||||||
|
($required ? 'required' : 'nullable'),
|
||||||
|
function (string $attribute, $value, callable $fail) use ($sizes) {
|
||||||
|
return $this->validatePicture($attribute, $value, $fail, $sizes);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate picture.
|
||||||
|
*
|
||||||
|
* @param string $attribute
|
||||||
|
* @param mixed $value
|
||||||
|
* @param callback $fail
|
||||||
|
* @param object $sizes
|
||||||
|
* @return void
|
||||||
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||||
|
*/
|
||||||
|
private function validatePicture(string $attribute, mixed $value, callable $fail, object $sizes)
|
||||||
|
{
|
||||||
|
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
||||||
|
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/** @var string */
|
||||||
|
$fileFullPath = $this->getUploadedFileFullPath($value, $useStorage);
|
||||||
|
if (
|
||||||
|
!\in_array($this->getUploadedFileMimeType($value, $useStorage), [
|
||||||
|
'image/jpeg', 'image/jpg', 'image/png', 'image/gif'
|
||||||
|
])
|
||||||
|
) {
|
||||||
|
$fail(trans(":attribute doit être une image de type 'image/jpeg,image/jpg,image/png,image/gif'"));
|
||||||
|
}
|
||||||
|
$filesize = \filesize($fileFullPath);
|
||||||
|
$maxSize = 6 * 1024 * 1024;
|
||||||
|
if ($filesize === false || $filesize > $maxSize) {
|
||||||
|
$fail(trans(':attribute doit être inférieur à :size Mo', ['size' => $maxSize / (1024 * 1024)]));
|
||||||
|
}
|
||||||
|
if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) {
|
||||||
|
$fail(trans(":attribute impossible de valider les dimensions"));
|
||||||
|
} else {
|
||||||
|
$width = intval($dimensions[0]);
|
||||||
|
$height = intval($dimensions[1]);
|
||||||
|
|
||||||
|
$xMessage = trans(
|
||||||
|
":attribute la largeur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
|
||||||
|
);
|
||||||
|
if ($sizes->minWith === $sizes->maxWith) {
|
||||||
|
$xMessage = trans(":attribute la largeur doit être de {$sizes->minWith}px");
|
||||||
|
}
|
||||||
|
$yMessage = trans(
|
||||||
|
":attribute la hauteur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
|
||||||
|
);
|
||||||
|
if ($sizes->minHeight === $sizes->maxHeight) {
|
||||||
|
$yMessage = trans(":attribute la hauteur doit être de {$sizes->minWith}px");
|
||||||
|
}
|
||||||
|
if (($width < $sizes->minWith) or ($width > $sizes->maxWith)) {
|
||||||
|
$fail($xMessage);
|
||||||
|
}
|
||||||
|
if (($height < $sizes->minHeight) or ($height > $sizes->maxHeight)) {
|
||||||
|
$fail($yMessage);
|
||||||
|
}
|
||||||
|
} //end if
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges picture field with request data.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function mergePicture(string $name = 'picture'): void
|
||||||
|
{
|
||||||
|
$picturePath = $this->{$name};
|
||||||
|
if (is_string($picturePath)) {
|
||||||
|
$this->merge(["{$name}Validate" => []]);
|
||||||
|
// ! Empty picture.
|
||||||
|
if ($picturePath === 'false') {
|
||||||
|
// * Empty picture and exit
|
||||||
|
$this->merge([$name => []]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$decodedPath = \urldecode($picturePath);
|
||||||
|
$this->merge([
|
||||||
|
"{$name}Validate" => array_merge(
|
||||||
|
$this->{"{$name}Validate"},
|
||||||
|
[\public_path(ltrim($decodedPath, '/'))]
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
$changedPicture = ltrim($decodedPath, '/');
|
||||||
|
$this->merge([
|
||||||
|
$name => $changedPicture
|
||||||
|
]);
|
||||||
|
} //end if
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges pictures fields with request data.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function mergePictures(string $name = 'pictures'): void
|
||||||
|
{
|
||||||
|
$pictures = $this->{$name};
|
||||||
|
if (is_array($pictures)) {
|
||||||
|
$this->merge(["{$name}Validate" => []]);
|
||||||
|
foreach ($pictures as $key => $picturePath) {
|
||||||
|
// ! Empty picture.
|
||||||
|
if ($picturePath === 'false') {
|
||||||
|
// * Empty picture and exit
|
||||||
|
$this->merge([$name => []]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$decodedPath = \urldecode($picturePath);
|
||||||
|
$this->merge([
|
||||||
|
"{$name}Validate" => array_merge(
|
||||||
|
$this->{"{$name}Validate"},
|
||||||
|
[\public_path(ltrim($decodedPath, '/'))]
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
$changedPicture = $this->{$name};
|
||||||
|
$changedPicture[$key] = ltrim($decodedPath, '/');
|
||||||
|
$this->merge([
|
||||||
|
$name => $changedPicture
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} //end if
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file full path.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @param boolean $useStorage
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getUploadedFileFullPath(string $value, bool $useStorage): string
|
||||||
|
{
|
||||||
|
return !$useStorage ? (realpath($value) ?: $value) : Storage::path($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file mimetype.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @param boolean $useStorage
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
private function getUploadedFileMimeType(string $value, bool $useStorage)
|
||||||
|
{
|
||||||
|
return !$useStorage ? File::mimeType($value) : Storage::mimeType($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
artisan
Executable file
53
artisan
Executable file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
define('LARAVEL_START', microtime(true));
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Register The Auto Loader
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Composer provides a convenient, automatically generated class loader
|
||||||
|
| for our application. We just need to utilize it! We'll require it
|
||||||
|
| into the script here so that we do not have to worry about the
|
||||||
|
| loading of any of our classes manually. It's great to relax.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
require __DIR__.'/vendor/autoload.php';
|
||||||
|
|
||||||
|
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Run The Artisan Application
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When we run the console application, the current CLI command will be
|
||||||
|
| executed in this console and the response sent back to a terminal
|
||||||
|
| or another output device for the developers. Here goes nothing!
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
||||||
|
|
||||||
|
$status = $kernel->handle(
|
||||||
|
$input = new Symfony\Component\Console\Input\ArgvInput,
|
||||||
|
new Symfony\Component\Console\Output\ConsoleOutput
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Shutdown The Application
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Once Artisan has finished running, we will fire off the shutdown events
|
||||||
|
| so that any final work may be done by the application before we shut
|
||||||
|
| down the process. This is the last thing to happen to the request.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$kernel->terminate($input, $status);
|
||||||
|
|
||||||
|
exit($status);
|
||||||
55
bootstrap/app.php
Normal file
55
bootstrap/app.php
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Create The Application
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The first thing we will do is create a new Laravel application instance
|
||||||
|
| which serves as the "glue" for all the components of Laravel, and is
|
||||||
|
| the IoC container for the system binding all of the various parts.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$app = new Illuminate\Foundation\Application(
|
||||||
|
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Bind Important Interfaces
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Next, we need to bind some important interfaces into the container so
|
||||||
|
| we will be able to resolve them when needed. The kernels serve the
|
||||||
|
| incoming requests to this application from both the web and CLI.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$app->singleton(
|
||||||
|
Illuminate\Contracts\Http\Kernel::class,
|
||||||
|
App\Http\Kernel::class
|
||||||
|
);
|
||||||
|
|
||||||
|
$app->singleton(
|
||||||
|
Illuminate\Contracts\Console\Kernel::class,
|
||||||
|
App\Console\Kernel::class
|
||||||
|
);
|
||||||
|
|
||||||
|
$app->singleton(
|
||||||
|
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||||
|
App\Exceptions\Handler::class
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Return The Application
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This script returns the application instance. The instance is given to
|
||||||
|
| the calling script so we can separate the building of the instances
|
||||||
|
| from the actual running of the application and sending responses.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
return $app;
|
||||||
2
bootstrap/cache/.gitignore
vendored
Normal file
2
bootstrap/cache/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
||||||
91
composer.json
Normal file
91
composer.json
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
{
|
||||||
|
"name": "laravel/laravel",
|
||||||
|
"type": "project",
|
||||||
|
"description": "The Laravel Framework.",
|
||||||
|
"keywords": [
|
||||||
|
"framework",
|
||||||
|
"laravel"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1",
|
||||||
|
"carlos-meneses/laravel-mpdf": "^2.1",
|
||||||
|
"diglactic/laravel-breadcrumbs": "^8.0",
|
||||||
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
|
"kwaadpepper/image-resizer": "^2.1",
|
||||||
|
"laravel/framework": "^10.0",
|
||||||
|
"laravel/tinker": "^2.8"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"fakerphp/faker": "^1.9.1",
|
||||||
|
"kitloong/laravel-migrations-generator": "^6.8",
|
||||||
|
"krlove/eloquent-model-generator": "dev-l10-compatibility",
|
||||||
|
"laravel-lang/common": "^4.0",
|
||||||
|
"laravel/pint": "^1.0",
|
||||||
|
"laravel/sail": "^1.18",
|
||||||
|
"mockery/mockery": "^1.4.4",
|
||||||
|
"nunomaduro/collision": "^7.0",
|
||||||
|
"phpunit/phpunit": "^10.0",
|
||||||
|
"slevomat/coding-standard": "^8.12",
|
||||||
|
"spatie/laravel-ignition": "^2.0",
|
||||||
|
"thedoctor0/laravel-factory-generator": "^1.2"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\": "app/",
|
||||||
|
"Database\\Factories\\": "database/factories/",
|
||||||
|
"Database\\Seeders\\": "database/seeders/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/laravel-shift/eloquent-model-generator.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"refresh": [
|
||||||
|
"@php artisan optimize:clear",
|
||||||
|
"@php artisan clear-compiled",
|
||||||
|
"@php artisan view:clear",
|
||||||
|
"@php artisan route:clear",
|
||||||
|
"@php artisan config:clear",
|
||||||
|
"@php artisan cache:clear"
|
||||||
|
],
|
||||||
|
"post-autoload-dump": [
|
||||||
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
|
"@php artisan package:discover --ansi"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||||
|
],
|
||||||
|
"post-root-package-install": [
|
||||||
|
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||||
|
],
|
||||||
|
"post-create-project-cmd": [
|
||||||
|
"@php artisan key:generate --ansi"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"dont-discover": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"preferred-install": "dist",
|
||||||
|
"sort-packages": true,
|
||||||
|
"allow-plugins": {
|
||||||
|
"pestphp/pest-plugin": true,
|
||||||
|
"php-http/discovery": true,
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"prefer-stable": true
|
||||||
|
}
|
||||||
10313
composer.lock
generated
Normal file
10313
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
216
config/app.php
Normal file
216
config/app.php
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value is the name of your application. This value is used when the
|
||||||
|
| framework needs to place the application's name in a notification or
|
||||||
|
| any other location as required by the application or its packages.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'name' => env('APP_NAME', 'Laravel'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Environment
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value determines the "environment" your application is currently
|
||||||
|
| running in. This may determine how you prefer to configure various
|
||||||
|
| services the application utilizes. Set this in your ".env" file.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'env' => env('APP_ENV', 'production'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Debug Mode
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When your application is in debug mode, detailed error messages with
|
||||||
|
| stack traces will be shown on every error that occurs within your
|
||||||
|
| application. If disabled, a simple generic error page is shown.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'debug' => (bool)env('APP_DEBUG', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application URL
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This URL is used by the console to properly generate URLs when using
|
||||||
|
| the Artisan command line tool. You should set this to the root of
|
||||||
|
| your application so that it is used when running Artisan tasks.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'url' => env('APP_URL', 'http://localhost'),
|
||||||
|
|
||||||
|
'asset_url' => env('ASSET_URL', '/'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Timezone
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the default timezone for your application, which
|
||||||
|
| will be used by the PHP date and date-time functions. We have gone
|
||||||
|
| ahead and set this to a sensible default for you out of the box.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timezone' => 'Europe/Paris',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Locale Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The application locale determines the default locale that will be used
|
||||||
|
| by the translation service provider. You are free to set this value
|
||||||
|
| to any of the locales which will be supported by the application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'locale' => 'fr',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Fallback Locale
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The fallback locale determines the locale to use when the current one
|
||||||
|
| is not available. You may change the value to correspond to any of
|
||||||
|
| the language folders that are provided through your application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'fallback_locale' => 'fr',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Faker Locale
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This locale will be used by the Faker PHP library when generating fake
|
||||||
|
| data for your database seeds. For example, this will be used to get
|
||||||
|
| localized telephone numbers, street address information and more.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'faker_locale' => 'fr_FR',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Encryption Key
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This key is used by the Illuminate encrypter service and should be set
|
||||||
|
| to a random, 32 character string, otherwise these encrypted strings
|
||||||
|
| will not be safe. Please do this before deploying an application!
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'key' => env('APP_KEY'),
|
||||||
|
|
||||||
|
'cipher' => 'AES-256-CBC',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Maintenance Mode Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These configuration options determine the driver used to determine and
|
||||||
|
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
||||||
|
| allow maintenance mode to be controlled across multiple machines.
|
||||||
|
|
|
||||||
|
| Supported drivers: "file", "cache"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'maintenance' => [
|
||||||
|
'driver' => 'file',
|
||||||
|
// 'store' 'redis'
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Autoloaded Service Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The service providers listed here will be automatically loaded on the
|
||||||
|
| request to your application. Feel free to add your own services to
|
||||||
|
| this array to grant expanded functionality to your applications.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'providers' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Laravel Framework Service Providers...
|
||||||
|
*/
|
||||||
|
|
||||||
|
Illuminate\Auth\AuthServiceProvider::class,
|
||||||
|
Illuminate\Broadcasting\BroadcastServiceProvider::class,
|
||||||
|
Illuminate\Bus\BusServiceProvider::class,
|
||||||
|
Illuminate\Cache\CacheServiceProvider::class,
|
||||||
|
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
|
||||||
|
Illuminate\Cookie\CookieServiceProvider::class,
|
||||||
|
Illuminate\Database\DatabaseServiceProvider::class,
|
||||||
|
Illuminate\Encryption\EncryptionServiceProvider::class,
|
||||||
|
Illuminate\Filesystem\FilesystemServiceProvider::class,
|
||||||
|
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
|
||||||
|
Illuminate\Hashing\HashServiceProvider::class,
|
||||||
|
Illuminate\Mail\MailServiceProvider::class,
|
||||||
|
Illuminate\Notifications\NotificationServiceProvider::class,
|
||||||
|
Illuminate\Pagination\PaginationServiceProvider::class,
|
||||||
|
Illuminate\Pipeline\PipelineServiceProvider::class,
|
||||||
|
Illuminate\Queue\QueueServiceProvider::class,
|
||||||
|
Illuminate\Redis\RedisServiceProvider::class,
|
||||||
|
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
|
||||||
|
Illuminate\Session\SessionServiceProvider::class,
|
||||||
|
Illuminate\Translation\TranslationServiceProvider::class,
|
||||||
|
Illuminate\Validation\ValidationServiceProvider::class,
|
||||||
|
Illuminate\View\ViewServiceProvider::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Package Service Providers...
|
||||||
|
*/
|
||||||
|
|
||||||
|
Krlove\EloquentModelGenerator\Provider\GeneratorServiceProvider::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Application Service Providers...
|
||||||
|
*/
|
||||||
|
|
||||||
|
App\Providers\AppServiceProvider::class,
|
||||||
|
App\Providers\AuthServiceProvider::class,
|
||||||
|
App\Providers\EventServiceProvider::class,
|
||||||
|
App\Providers\RouteServiceProvider::class,
|
||||||
|
App\Providers\TranslationServiceProvider::class,
|
||||||
|
App\Providers\ViewServiceProvider::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Class Aliases
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This array of class aliases will be registered when this application
|
||||||
|
| is started. However, feel free to register as many as you wish as
|
||||||
|
| the aliases are "lazy" loaded so they don't hinder performance.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'aliases' => Facade::defaultAliases()->merge([])->toArray(),
|
||||||
|
];
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue