Merge branch 'develop' into trunk
This commit is contained in:
commit
79ddb51a74
8568 changed files with 60023 additions and 1771105 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
|
||||
63
.env.example
Normal file
63
.env.example
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
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}"
|
||||
|
||||
# Sentry
|
||||
SENTRY_LARAVEL_DSN=
|
||||
|
||||
GOOGLE_MAPS_KEY=
|
||||
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
|
||||
50
.gitignore
vendored
50
.gitignore
vendored
|
|
@ -1,24 +1,26 @@
|
|||
#fichiers systemes
|
||||
.bash_history
|
||||
.bash_profile
|
||||
.selected_editor
|
||||
.ssh/
|
||||
.upload/
|
||||
.viminfo
|
||||
|
||||
# ignore log file
|
||||
*.log
|
||||
log.txt
|
||||
|
||||
# ignore nodejs files
|
||||
node_modules
|
||||
|
||||
# ignore fichiers de preuve de gain
|
||||
wp-content/uploads/PDFgain/*
|
||||
!wp-content/uploads/PDFgain/.gitkeep
|
||||
|
||||
# ignore upload file
|
||||
content/uploads/*
|
||||
!content/uploads/.htaccess
|
||||
|
||||
version-checker/*
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpunit.result.cache
|
||||
.stylelintcache
|
||||
/.fleet
|
||||
/.idea
|
||||
/.phpunit.cache
|
||||
/.vscode/launch.json
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/cache
|
||||
/public/hot
|
||||
/public/medias
|
||||
/public/sitemap.xml
|
||||
/public/storage
|
||||
/public/uploads
|
||||
/storage/*.key
|
||||
/vendor
|
||||
auth.json
|
||||
docker-compose.override.yml
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.vscode/settings.json
|
||||
|
|
|
|||
11
.gitlab-ci.yml
Normal file
11
.gitlab-ci.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
include:
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'lint/lint.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'security/security.yml'
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- security
|
||||
11
.gitlab/issue_templates/bug.md
Normal file
11
.gitlab/issue_templates/bug.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
## Comportement constaté
|
||||
|
||||
|
||||
## Comportement attendu
|
||||
|
||||
|
||||
## Solution envisagée
|
||||
|
||||
|
||||
## Étapes pour la reproduction du bug
|
||||
*
|
||||
7
.gitlab/issue_templates/feature.md
Normal file
7
.gitlab/issue_templates/feature.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
## Présentation du besoin
|
||||
|
||||
|
||||
## Implémentation
|
||||
|
||||
|
||||
## Maquettes, documentations...
|
||||
415
.htaccess
415
.htaccess
|
|
@ -1,415 +0,0 @@
|
|||
# protection contre la lecture des répertoires
|
||||
Options All -Indexes
|
||||
|
||||
# Masquer les informations du serveur
|
||||
ServerSignature Off
|
||||
|
||||
RewriteEngine on
|
||||
|
||||
# Protect wp-config.php
|
||||
<FilesMatch ^wp-config.php$>
|
||||
deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Protect .htaccess et .htpasswds
|
||||
<Files ~ "^.*\.([Hh][Tt][AaPp])">
|
||||
order allow,deny
|
||||
deny from all
|
||||
</Files>
|
||||
|
||||
# Protect debug.log
|
||||
<Files debug.log>
|
||||
order allow,deny
|
||||
deny from all
|
||||
</Files>
|
||||
|
||||
# Protect sql files
|
||||
<FilesMatch "\.sql">
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# protection des fichiers readme et licence wordpress
|
||||
<files readme.html>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</files>
|
||||
<files license.txt>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</files>
|
||||
<files readme.txt>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</files>
|
||||
|
||||
# protection des fichiers sys .git
|
||||
RedirectMatch 404 /\.
|
||||
|
||||
#Bloquer l'indexation des fichiers PDF
|
||||
<files ~ "\.(doc|docx|pdf)$">
|
||||
Header set X-Robots-Tag "noindex, nofollow"
|
||||
</Files>
|
||||
|
||||
# Rules to disable XML-RPC
|
||||
<files xmlrpc.php>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</files>
|
||||
|
||||
# Cacher l'identifiant d'un auteur
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteCond %{QUERY_STRING} ^author=([0-9]*)
|
||||
RewriteRule .* - [F]
|
||||
</IfModule>
|
||||
|
||||
### FILTRE CONTRE XSS, REDIRECTIONS HTTP, base64_encode, VARIABLE PHP GLOBALS VIA URL, MODIFIER VARIABLE _REQUEST VIA URL, TEST DE FAILLE PHP, INJECTION SQL SIMPLE
|
||||
RewriteCond %{REQUEST_METHOD} (GET|POST) [NC]
|
||||
RewriteCond %{QUERY_STRING} ^(.*)(%3C|<)/?script(.*)$ [NC,OR]
|
||||
RewriteCond %{QUERY_STRING} ^(.*)(%3D|=)?javascript(%3A|:)(.*)$ [NC,OR]
|
||||
RewriteCond %{QUERY_STRING} ^(.*)document\.location\.href(.*)$ [OR]
|
||||
RewriteCond %{QUERY_STRING} ^.*(%24&x).* [NC,OR]
|
||||
RewriteCond %{QUERY_STRING} ^.*(127\.0).* [NC,OR]
|
||||
RewriteCond %{QUERY_STRING} ^(.*)(%3D|=)(https?|ftp|mosConfig)(%3A|:)//(.*)$ [NC,OR] ## ATTENTION A CETTE REGLE. ELLE PEUT CASSER CERTAINES REDIRECTIONS RESSEMBLANT A: http://www.truc.fr/index.php?r=http://www.google.fr ##
|
||||
RewriteCond %{QUERY_STRING} ^.*(_encode|localhost|loopback).* [NC,OR]
|
||||
RewriteCond %{QUERY_STRING} ^(.*)GLOBALS(=|[|%[0-9A-Z]{0,2})(.*)$ [OR]
|
||||
RewriteCond %{QUERY_STRING} ^(.*)_REQUEST(=|[|%[0-9A-Z]{0,2})(.*)$ [OR]
|
||||
RewriteCond %{QUERY_STRING} ^(.*)(SELECT(%20|\+)|UNION(%20|\+)ALL|INSERT(%20|\+)|DELETE(%20|\+)|CHAR\(|UPDATE(%20|\+)|REPLACE(%20|\+)|LIMIT(%20|\+)|CONCAT(%20|\+)|DECLARE(%20|\+))(.*)$ [NC]
|
||||
RewriteRule (.*) - [F]
|
||||
|
||||
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
# A TESTER la page n'accepte que les scripts provenant du même nom de domaine et de google.com (par exemple)
|
||||
#Header set Content-Security-Policy "script-src 'self' https://www.google.com"
|
||||
|
||||
# Protection contre le clickjacking. Interdit que le site soit intégré en iframe
|
||||
Header always set X-FRAME-OPTIONS "DENY"
|
||||
|
||||
# Bloque la totalité du contenu lorsqu'une attaque XSS est suspectée
|
||||
Header always set X-XSS-Protection "1; mode=block"
|
||||
|
||||
#Désactive la détection automatique du type des ressources
|
||||
Header always set X-Content-Type-Options "nosniff"
|
||||
|
||||
|
||||
# protege les cookies d'être modifiés par le client
|
||||
#Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
|
||||
</IfModule>
|
||||
|
||||
# BEGIN DEFLATE COMPRESSION
|
||||
<IfModule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE application/javascript
|
||||
AddOutputFilterByType DEFLATE application/rss+xml
|
||||
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
|
||||
AddOutputFilterByType DEFLATE application/x-font
|
||||
AddOutputFilterByType DEFLATE application/x-font-opentype
|
||||
AddOutputFilterByType DEFLATE application/x-font-otf
|
||||
AddOutputFilterByType DEFLATE application/x-font-truetype
|
||||
AddOutputFilterByType DEFLATE application/x-font-ttf
|
||||
AddOutputFilterByType DEFLATE application/x-javascript
|
||||
AddOutputFilterByType DEFLATE application/xhtml+xml
|
||||
AddOutputFilterByType DEFLATE application/xml
|
||||
AddOutputFilterByType DEFLATE font/opentype
|
||||
AddOutputFilterByType DEFLATE font/otf
|
||||
AddOutputFilterByType DEFLATE font/ttf
|
||||
AddOutputFilterByType DEFLATE image/svg+xml
|
||||
AddOutputFilterByType DEFLATE image/x-icon
|
||||
AddOutputFilterByType DEFLATE text/css
|
||||
AddOutputFilterByType DEFLATE text/html
|
||||
AddOutputFilterByType DEFLATE text/javascript
|
||||
AddOutputFilterByType DEFLATE text/plain
|
||||
AddOutputFilterByType DEFLATE text/xml
|
||||
</IfModule>
|
||||
# END DEFLATE COMPRESSION
|
||||
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
ExpiresDefault "access plus 1 month"
|
||||
ExpiresByType text/html "access plus 0 seconds"
|
||||
ExpiresByType text/xml "access plus 0 seconds"
|
||||
ExpiresByType application/xml "access plus 0 seconds"
|
||||
ExpiresByType application/json "access plus 0 seconds"
|
||||
ExpiresByType application/pdf "access plus 0 seconds"
|
||||
ExpiresByType application/rss+xml "access plus 1 hour"
|
||||
ExpiresByType application/atom+xml "access plus 1 hour"
|
||||
ExpiresByType application/x-font-ttf "access plus 1 month"
|
||||
ExpiresByType font/opentype "access plus 1 month"
|
||||
ExpiresByType application/x-font-woff "access plus 1 month"
|
||||
ExpiresByType application/x-font-woff2 "access plus 1 month"
|
||||
ExpiresByType image/svg+xml "access plus 1 month"
|
||||
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
|
||||
ExpiresByType image/jpg "access plus 1 month"
|
||||
ExpiresByType image/jpeg "access plus 1 month"
|
||||
ExpiresByType image/gif "access plus 1 month"
|
||||
ExpiresByType image/png "access plus 1 month"
|
||||
ExpiresByType video/ogg "access plus 1 month"
|
||||
ExpiresByType audio/ogg "access plus 1 month"
|
||||
ExpiresByType video/mp4 "access plus 1 month"
|
||||
ExpiresByType video/webm "access plus 1 month"
|
||||
ExpiresByType text/css "access plus 6 month"
|
||||
ExpiresByType application/javascript "access plus 6 month"
|
||||
ExpiresByType application/x-shockwave-flash "access plus 1 week"
|
||||
ExpiresByType image/x-icon "access plus 1 week"
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
<FilesMatch "\\.(ico|jpe?g|png|gif|swf|svg)$">
|
||||
Header set Cache-Control "max-age=2592000, public"
|
||||
</FilesMatch>
|
||||
<FilesMatch "\\.(css)$">
|
||||
Header set Cache-Control "max-age=604800, public"
|
||||
</FilesMatch>
|
||||
<FilesMatch "\\.(js)$">
|
||||
Header set Cache-Control "max-age=604800, private"
|
||||
</FilesMatch>
|
||||
<filesmatch "\\.(html|htm)$">
|
||||
Header set Cache-Control "max-age=5, public"
|
||||
</filesmatch>
|
||||
<filesmatch "\\.(woff)$">
|
||||
Header set Cache-Control "max-age=604800, public"
|
||||
</filesmatch>
|
||||
</IfModule>
|
||||
|
||||
|
||||
<ifModule mod_gzip.c>
|
||||
mod_gzip_on Yes
|
||||
mod_gzip_dechunk Yes
|
||||
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
|
||||
mod_gzip_item_include handler ^cgi-script$
|
||||
mod_gzip_item_include mime ^text/.*
|
||||
mod_gzip_item_include mime ^application/x-javascript.*
|
||||
mod_gzip_item_exclude mime ^image/.*
|
||||
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
|
||||
</ifModule>
|
||||
|
||||
Header unset Pragma
|
||||
FileETag None
|
||||
Header unset ETag
|
||||
|
||||
# Enable HackRepair.com's blacklist
|
||||
# Start Abuse Agent Blocking
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Mozilla.*Indy" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Mozilla.*NEWT" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^$" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Maxthon$" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^SeaMonkey$" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Acunetix" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^binlar" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^BlackWidow" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Bolt 0" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^BOT for JCE" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Bot mailto\:craftbot@yahoo\.com" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^casper" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^checkprivacy" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^ChinaClaw" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^clshttp" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^cmsworldmap" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Custo" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Default Browser 0" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^diavol" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^DIIbot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^DISCo" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^dotbot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Download Demon" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^eCatch" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^EirGrabber" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^EmailCollector" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^EmailSiphon" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^EmailWolf" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Express WebPictures" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^extract" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^ExtractorPro" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^EyeNetIE" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^feedfinder" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^FHscan" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^FlashGet" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^flicky" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^g00g1e" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^GetRight" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^GetWeb\!" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Go\!Zilla" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Go\-Ahead\-Got\-It" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^grab" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^GrabNet" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Grafula" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^harvest" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^HMView" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Image Stripper" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Image Sucker" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^InterGET" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Internet Ninja" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^InternetSeer\.com" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^jakarta" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Java" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^JetCar" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^JOC Web Spider" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^kanagawa" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^kmccrew" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^larbin" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^LeechFTP" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^libwww" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Mass Downloader" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^microsoft\.url" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^MIDown tool" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^miner" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Mister PiX" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^MSFrontPage" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Navroad" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^NearSite" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Net Vampire" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^NetAnts" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^NetSpider" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^NetZIP" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^nutch" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Octopus" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Offline Explorer" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Offline Navigator" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^PageGrabber" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Papa Foto" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^pavuk" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^pcBrowser" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^PeoplePal" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^planetwork" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^psbot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^purebot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^pycurl" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^RealDownload" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^ReGet" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Rippers 0" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^sitecheck\.internetseer\.com" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^SiteSnagger" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^skygrid" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^SmartDownload" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^sucker" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^SuperBot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^SuperHTTP" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Surfbot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^tAkeOut" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Teleport Pro" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Toata dragostea mea pentru diavola" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^turnit" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^vikspider" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^VoidEYE" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Web Image Collector" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebAuto" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebBandit" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebCopier" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebFetch" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebGo IS" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebLeacher" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebReaper" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebSauger" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Website eXtractor" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Website Quester" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebStripper" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebWhacker" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WebZIP" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Widow" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WPScan" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WWW\-Mechanize" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^WWWOFFLE" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Xaldon WebSpider" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^Zeus" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "^zmeu" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "360Spider" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "CazoodleBot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "discobot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "EasouSpider" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "ecxi" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "GT\:\:WWW" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "heritrix" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "HTTP\:\:Lite" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "HTTrack" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "ia_archiver" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "id\-search" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "IDBot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "Indy Library" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "IRLbot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "ISC Systems iRc Search 2\.1" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "LinksCrawler" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "LinksManager\.com_bot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "linkwalker" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "lwp\-trivial" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "MFC_Tear_Sample" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "Microsoft URL Control" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "Missigua Locator" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "MJ12bot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "panscient\.com" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "PECL\:\:HTTP" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "PHPCrawl" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "PleaseCrawl" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "SBIder" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "SearchmetricsBot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "SeznamBot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "Snoopy" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "Steeler" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "URI\:\:Fetch" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "urllib" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "Web Sucker" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "webalta" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "WebCollage" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "Wells Search II" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "WEP Search" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "XoviBot" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "YisouSpider" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "zermelo" [NC,OR]
|
||||
RewriteCond %{HTTP_USER_AGENT} "ZyBorg" [NC,OR]
|
||||
# End Abuse Agent Blocking
|
||||
# Start Abuse HTTP Referrer Blocking
|
||||
RewriteCond %{HTTP_REFERER} "^https?://(?:[^/]+\.)?semalt\.com" [NC,OR]
|
||||
RewriteCond %{HTTP_REFERER} "^https?://(?:[^/]+\.)?kambasoft\.com" [NC,OR]
|
||||
RewriteCond %{HTTP_REFERER} "^https?://(?:[^/]+\.)?savetubevideo\.com" [NC]
|
||||
# End Abuse HTTP Referrer Blocking
|
||||
RewriteRule ^.* - [F,L]
|
||||
# End HackRepair.com Blacklist, http://pastebin.com/u/hackrepair
|
||||
|
||||
# mode maintenance (commentez le bloque BEGIN WordPress)
|
||||
#<IfModule mod_rewrite.c>
|
||||
# Options +FollowSymlinks
|
||||
# RewriteEngine on
|
||||
# RewriteCond %{REQUEST_URI} !/maintenance.html$
|
||||
# # use X-FORWARDED-FOR whith haproxy
|
||||
# RewriteCond %{HTTP:X-FORWARDED-FOR} !86.65.205.242
|
||||
# RewriteRule $ /maintenance.html [R=302,L]
|
||||
#</IfModule>
|
||||
|
||||
# BEGIN WordPress
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteRule ^index\.php$ - [L]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule . /index.php [L]
|
||||
</IfModule>
|
||||
|
||||
# END WordPress
|
||||
|
||||
## REDIRECTIONS PERMANENTES ##
|
||||
RedirectPermanent /de/accueil /de/
|
||||
RedirectPermanent /home /
|
||||
RedirectPermanent /de/home /de/
|
||||
RedirectPermanent /de/our-products /products/
|
||||
RedirectPermanent /de/our-values /de/konzept/
|
||||
RedirectPermanent /de/our-breeding-farm-in-pictures /de/konzept/
|
||||
RedirectPermanent /our-breeding-farm-in-pictures /concept/
|
||||
RedirectPermanent /testimonies-of-our-breeders /concept/
|
||||
RedirectPermanent /sharebutton.to /
|
||||
RedirectPermanent /our-values /concept/
|
||||
RedirectPermanent /our-products /products/
|
||||
RedirectPermanent /de/nos-valeurs /de/konzept/
|
||||
RedirectPermanent /de/contact /de/kontakt/
|
||||
RedirectPermanent /contact /contact-us/
|
||||
RedirectPermanent /de/testimonies-of-our-breeders /de/konzept/
|
||||
RedirectPermanent /de/our-products/?categ=oie /de/produkte/
|
||||
RedirectPermanent /de/our-breeding-farm-in-pictures/?categ=oie /de/produkte/
|
||||
RedirectPermanent /de/our-products/?categ=canard /de/produkte/
|
||||
RedirectPermanent /de/our-breeding-farm-in-pictures/?categ=canard /de/produkte/
|
||||
RedirectPermanent /our-breeding-farm-in-pictures/?categ=canard /products/
|
||||
RedirectPermanent /our-breeding-farm-in-pictures/?categ=poulet /products/
|
||||
RedirectPermanent /de/our-breeding-farm-in-pictures/?categ=poulet /de/produkte/
|
||||
RedirectPermanent /de/our-products/?categ=poulet /de/produkte/
|
||||
RedirectPermanent /our-products/?categ=poulet /products/
|
||||
RedirectPermanent /our-products/?categ=canard /products/
|
||||
RedirectPermanent /de/legal-notice /de/impressum/
|
||||
43
.stylelintrc.json
Normal file
43
.stylelintrc.json
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"extends": [
|
||||
"stylelint-config-prettier",
|
||||
"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"
|
||||
],
|
||||
"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,
|
||||
"declaration-colon-space-after": "always-single-line",
|
||||
"function-parentheses-space-inside": "never-single-line",
|
||||
"declaration-colon-newline-after": null,
|
||||
"scss/double-slash-comment-empty-line-before": [
|
||||
"always",
|
||||
{
|
||||
"ignore": [
|
||||
"between-comments",
|
||||
"stylelint-commands",
|
||||
"inside-block"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
25
.vscode/settings.json
vendored
Normal file
25
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.activeBackground": "#d6de61",
|
||||
"activityBar.background": "#d6de61",
|
||||
"activityBar.foreground": "#15202b",
|
||||
"activityBar.inactiveForeground": "#15202b99",
|
||||
"activityBarBadge.background": "#21969e",
|
||||
"activityBarBadge.foreground": "#e7e7e7",
|
||||
"commandCenter.border": "#15202b99",
|
||||
"sash.hoverBorder": "#d6de61",
|
||||
"statusBar.background": "#cbd537",
|
||||
"statusBar.foreground": "#15202b",
|
||||
"statusBarItem.hoverBackground": "#aab326",
|
||||
"statusBarItem.remoteBackground": "#cbd537",
|
||||
"statusBarItem.remoteForeground": "#15202b",
|
||||
"titleBar.activeBackground": "#cbd537",
|
||||
"titleBar.activeForeground": "#15202b",
|
||||
"titleBar.inactiveBackground": "#cbd53799",
|
||||
"titleBar.inactiveForeground": "#15202b99"
|
||||
},
|
||||
"peacock.remoteColor": "#CBD537",
|
||||
"intelephense.environment.phpVersion": "8.2.0",
|
||||
"intelephense.completion.fullyQualifyGlobalConstantsAndFunctions": true,
|
||||
"intelephense.phpdoc.useFullyQualifiedNames": true
|
||||
}
|
||||
6
README.md
Normal file
6
README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# TODO
|
||||
|
||||
- Creer https://console.cloud.google.com wenn mit truc pour ajouter la clé google map
|
||||
- Api pour storefinder cassée rules.wo-gilt-was.de
|
||||
|
||||
- passer le script en TS et le style pas en inline
|
||||
177
app/Console/Commands/CreateAdmin.php
Normal file
177
app/Console/Commands/CreateAdmin.php
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class CreateAdmin extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'user:create';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a backend admin user';
|
||||
|
||||
/**
|
||||
* The firstname of the new user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $firstname;
|
||||
|
||||
/**
|
||||
* The lastname of the new user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $lastname;
|
||||
|
||||
/**
|
||||
* The email of the new user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $email;
|
||||
|
||||
/**
|
||||
* The password of the new user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $password;
|
||||
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$this->firstname = null;
|
||||
$this->addFirstname();
|
||||
|
||||
$this->lastname = null;
|
||||
$this->addLastname();
|
||||
|
||||
$this->email = null;
|
||||
$this->addEmail();
|
||||
|
||||
$this->password = null;
|
||||
$this->addPassword();
|
||||
|
||||
$user = new User([
|
||||
'firstname' => $this->firstname,
|
||||
'lastname' => $this->lastname,
|
||||
'email' => $this->email,
|
||||
'password' => $this->password,
|
||||
]);
|
||||
$user->saveOrFail();
|
||||
|
||||
$this->info('User created 👌');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a firstname to the user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addFirstname(): void
|
||||
{
|
||||
while (is_null($this->firstname)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user firstname', 'Admin');
|
||||
$validator = Validator::make(['firstname' => $tmp], [
|
||||
'firstname' => 'required|min:3|max:255'
|
||||
]);
|
||||
$validator->validate();
|
||||
$this->firstname = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid firstname %s',
|
||||
\implode(',', collect($e->errors())->flatten()->all())
|
||||
));
|
||||
continue;
|
||||
} //end try
|
||||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a lastname to the user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addLastname(): void
|
||||
{
|
||||
while (is_null($this->lastname)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user lastname', 'Saïtama');
|
||||
$validator = Validator::make(['lastname' => $tmp], [
|
||||
'lastname' => 'required|min:3|max:255'
|
||||
]);
|
||||
$validator->validate();
|
||||
$this->lastname = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid lastname %s',
|
||||
\implode(',', collect($e->errors())->flatten()->all())
|
||||
));
|
||||
continue;
|
||||
} //end try
|
||||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an email to the user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addEmail(): void
|
||||
{
|
||||
while (is_null($this->email)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user email', 'equipe.web@ldc.fr');
|
||||
$validator = Validator::make(['email' => $tmp], [
|
||||
'email' => 'required|unique:users,email|email:rfc,dns'
|
||||
]);
|
||||
$validator->validate();
|
||||
$this->email = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid email %s',
|
||||
\implode(',', collect($e->errors())->flatten()->all())
|
||||
));
|
||||
continue;
|
||||
} //end try
|
||||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a password to the user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addPassword(): void
|
||||
{
|
||||
while (
|
||||
($this->password = $this->secret(
|
||||
(!\is_null($this->password) ? 'Failed to confirm, ' : '') . 'Type the wanted user password'
|
||||
)) !== $this->secret('Confirm the password')
|
||||
) {
|
||||
continue;
|
||||
}; //end while
|
||||
}
|
||||
}
|
||||
33
app/Console/Kernel.php
Normal file
33
app/Console/Kernel.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\SlidersStatusUpdate;
|
||||
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)
|
||||
{
|
||||
$schedule->job(SlidersStatusUpdate::class)->everyMinute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function commands()
|
||||
{
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
}
|
||||
47
app/Enums/Concepts/ColorsEnum.php
Normal file
47
app/Enums/Concepts/ColorsEnum.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Concepts;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum ColorsEnum: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case redwine = 1;
|
||||
case orange = 2;
|
||||
case blue = 3;
|
||||
case lightgreen = 4;
|
||||
case brown = 5;
|
||||
|
||||
/**
|
||||
* Custom added colors definition
|
||||
*/
|
||||
private const COLORS = [
|
||||
self::redwine->name => 'rgb(165 25 60)',
|
||||
self::orange->name => 'rgb(240 165 0)',
|
||||
self::blue->name => 'rgb(95 155 210)',
|
||||
self::lightgreen->name => 'rgb(180 190 0)',
|
||||
self::brown->name => 'rgb(95 40 45)',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Color
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function color(): string
|
||||
{
|
||||
return self::COLORS[$this->name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enum colors
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function toColors(): array
|
||||
{
|
||||
return self::COLORS;
|
||||
}
|
||||
}
|
||||
25
app/Enums/InputType.php
Normal file
25
app/Enums/InputType.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum InputType: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case boolean = 1;
|
||||
case dropdownArray = 2;
|
||||
case email = 3;
|
||||
case image = 4;
|
||||
case imageArray = 5;
|
||||
case labelArray = 6;
|
||||
case miniblocArray = 7;
|
||||
case number = 8;
|
||||
case selectEnum = 9;
|
||||
case password = 10;
|
||||
case string = 11;
|
||||
case text = 12;
|
||||
case url = 13;
|
||||
case videoVimeo = 14;
|
||||
}
|
||||
47
app/Enums/Products/CertificationsEnum.php
Normal file
47
app/Enums/Products/CertificationsEnum.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Products;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum CertificationsEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case haltungsform1 = 1;
|
||||
case haltungsform2 = 2;
|
||||
case haltungsform3 = 3;
|
||||
case haltungsform4 = 4;
|
||||
case ecc = 5;
|
||||
|
||||
/**
|
||||
* Custom added images definition
|
||||
*/
|
||||
private const IMAGES = [
|
||||
self::haltungsform1->name => "haltungsform1.png",
|
||||
self::haltungsform2->name => "haltungsform2.png",
|
||||
self::haltungsform3->name => "haltungsform3.png",
|
||||
self::haltungsform4->name => "haltungsform4.png",
|
||||
self::ecc->name => "ecc.png",
|
||||
];
|
||||
|
||||
/**
|
||||
* Get image
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function image(): string
|
||||
{
|
||||
return self::IMAGES[$this->name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enum images
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function toImages(): array
|
||||
{
|
||||
return self::IMAGES;
|
||||
}
|
||||
}
|
||||
49
app/Enums/Ranges/PictoEnum.php
Normal file
49
app/Enums/Ranges/PictoEnum.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Ranges;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum PictoEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case chicken = 1;
|
||||
case duck = 2;
|
||||
case turkey = 3;
|
||||
case soupchicken = 4;
|
||||
case guineafowl = 5;
|
||||
case goose = 6;
|
||||
|
||||
/**
|
||||
* Custom added images definition
|
||||
*/
|
||||
private const IMAGES = [
|
||||
self::chicken->name => "chicken.png",
|
||||
self::duck->name => "duck.png",
|
||||
self::turkey->name => "turkey.png",
|
||||
self::soupchicken->name => "soupchicken.png",
|
||||
self::guineafowl->name => "guineafowl.png",
|
||||
self::goose->name => "goose.png",
|
||||
];
|
||||
|
||||
/**
|
||||
* Get image
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function image(): string
|
||||
{
|
||||
return self::IMAGES[$this->name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enum images
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function toImages(): array
|
||||
{
|
||||
return self::IMAGES;
|
||||
}
|
||||
}
|
||||
14
app/Enums/Recipes/DifficultyEnum.php
Normal file
14
app/Enums/Recipes/DifficultyEnum.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Recipes;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum DifficultyEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case easy = 1;
|
||||
case medium = 2;
|
||||
case hard = 3;
|
||||
}
|
||||
12
app/Enums/Sliders/TypeEnum.php
Normal file
12
app/Enums/Sliders/TypeEnum.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Sliders;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum TypeEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case home = 1;
|
||||
}
|
||||
48
app/Exceptions/Handler.php
Normal file
48
app/Exceptions/Handler.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?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 for 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()
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
if (app()->bound('sentry')) {
|
||||
app('sentry')->captureException($e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
52
app/Http/Controllers/Bo/Auth/LoginController.php
Normal file
52
app/Http/Controllers/Bo/Auth/LoginController.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
use AuthenticatesUsers;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest:backend')->except('logout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the guard to be used during authentication.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
{
|
||||
return Auth::guard('backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application's login form.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showLoginForm()
|
||||
{
|
||||
return view('bo.auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo(): string
|
||||
{
|
||||
return response()->redirectToIntended()->getTargetUrl();
|
||||
}
|
||||
}
|
||||
33
app/Http/Controllers/Bo/Auth/ResetPasswordController.php
Normal file
33
app/Http/Controllers/Bo/Auth/ResetPasswordController.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Get the guard to be used during authentication.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard(): StatefulGuard
|
||||
{
|
||||
return Auth::guard('backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo(): string
|
||||
{
|
||||
return \route('bo.login');
|
||||
}
|
||||
}
|
||||
176
app/Http/Controllers/Bo/ConceptController.php
Normal file
176
app/Http/Controllers/Bo/ConceptController.php
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Concepts\StoreConceptRequest;
|
||||
use App\Http\Requests\Bo\Concepts\UpdateConceptRequest;
|
||||
use App\Models\Concept;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Models\MiniCrudModel;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ConceptController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use MiniCrudModel;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $concepts */
|
||||
$concepts = Concept::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$concepts,
|
||||
$request->search,
|
||||
null,
|
||||
'seo_title',
|
||||
'name',
|
||||
'title',
|
||||
'subtitle',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($concepts);
|
||||
$searchFields = trans('Name');
|
||||
|
||||
$conceptModels = $concepts->paginate(10);
|
||||
|
||||
return view('bo.pages.concepts.index', compact('conceptModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if (Concept::count() === 8) {
|
||||
return back()
|
||||
->with(
|
||||
'error',
|
||||
trans(
|
||||
'You already created 8 :models. Please delete or edit an existing one.',
|
||||
['models' => trans('models.classes.concepts')]
|
||||
)
|
||||
);
|
||||
}
|
||||
$conceptData = Concept::getEmptyData();
|
||||
|
||||
return view('bo.pages.concepts.create', compact('conceptData'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Concepts\StoreConceptRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreConceptRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$concept = new Concept();
|
||||
$concept->data = $concept->getEmptyData();
|
||||
$concept->fill(array_replace_recursive(
|
||||
\json_decode(\json_encode($concept->toArray()), true),
|
||||
$request->validated()
|
||||
));
|
||||
|
||||
if ($concept->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.concepts.edit', $concept)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.concepts'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.concepts'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Concept $concept
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Concept $concept)
|
||||
{
|
||||
return view('bo.pages.concepts.edit', [
|
||||
'conceptModel' => $concept
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Concepts\UpdateConceptRequest $request
|
||||
* @param \App\Models\Concept $concept
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateConceptRequest $request, Concept $concept)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $concept) {
|
||||
$concept->fill(array_replace_recursive(
|
||||
\json_decode(\json_encode($concept->toArray()), true),
|
||||
$request->validated()
|
||||
));
|
||||
|
||||
if ($concept->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.concepts.edit', $concept)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.concepts'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.concepts'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Concept $concept
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Concept $concept)
|
||||
{
|
||||
if ($concept->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.concepts.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.concepts'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.concepts'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
34
app/Http/Controllers/Bo/DashboardController.php
Normal file
34
app/Http/Controllers/Bo/DashboardController.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Dashboard Page
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('bo.pages.dashboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Chagne current locale on BO.
|
||||
*
|
||||
* @param string $lang
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function changeLang(string $lang): RedirectResponse
|
||||
{
|
||||
if (!\in_array($lang, config('app.locales'))) {
|
||||
$lang = config('app.fallback_locale');
|
||||
}
|
||||
session()->put('lang', $lang);
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
56
app/Http/Controllers/Bo/HomeController.php
Normal file
56
app/Http/Controllers/Bo/HomeController.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Homes\UpdateHomeRequest;
|
||||
use App\Models\Home;
|
||||
use App\Models\Product;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
$homeModel = Home::query()->firstOrFail();
|
||||
$products = Product::query()->where('status', true)->orderBy('label', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.homes.edit', compact('homeModel', 'products'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Homes\UpdateHomeRequest $request
|
||||
* @param \App\Models\Home $home
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateHomeRequest $request, Home $home)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $home) {
|
||||
$data = $request->validated();
|
||||
$home->fill($data);
|
||||
if ($home->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.homes.edit', $home)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.homes'))]
|
||||
));
|
||||
} //end if
|
||||
return back()->with('success', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.homes'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
176
app/Http/Controllers/Bo/ProductController.php
Normal file
176
app/Http/Controllers/Bo/ProductController.php
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Products\StoreProductRequest;
|
||||
use App\Http\Requests\Bo\Products\UpdateProductRequest;
|
||||
use App\Http\Requests\ProductIndexFilterRequest;
|
||||
use App\Models\Product;
|
||||
use App\Models\Range;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use HasPicture;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Http\Requests\ProductIndexFilterRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(ProductIndexFilterRequest $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $product */
|
||||
$product = Product::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$product,
|
||||
$request->search,
|
||||
null,
|
||||
'label',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($product);
|
||||
$searchFields = trans('Label');
|
||||
|
||||
$noOrder = false;
|
||||
if ($request->range_id) {
|
||||
$product->whereHas('range', fn (Builder $q) => $q->where('id', $request->range_id));
|
||||
$noOrder = true;
|
||||
}
|
||||
|
||||
|
||||
$productModels = $product->paginate(10);
|
||||
$ranges = Range::query()->get();
|
||||
|
||||
return view('bo.pages.products.index', compact('ranges', 'productModels', 'searchFields', 'noOrder'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$rangeModels = Range::orderBy('label', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.products.create', compact('rangeModels'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Products\StoreProductRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreProductRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$product = new Product();
|
||||
$tmpNutrionnalValues = \collect($request->validated()['nutritionnal_values']);
|
||||
$tmpList = \collect($request->validated()['list']);
|
||||
$product->fill($request->validated());
|
||||
$product->nutritionnal_values = $tmpNutrionnalValues;
|
||||
$product->list = $tmpList;
|
||||
|
||||
if ($product->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.products.edit', $product)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Models\Product $product
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function edit(Product $product)
|
||||
{
|
||||
$rangeModels = Range::orderBy('label', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.products.edit', [
|
||||
'productModel' => $product,
|
||||
'rangeModels' => $rangeModels
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\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) {
|
||||
$tmpNutrionnalValues = \collect($request->validated()['nutritionnal_values']);
|
||||
$tmpList = \collect($request->validated()['list']);
|
||||
$product->fill($request->validated());
|
||||
$product->nutritionnal_values = $tmpNutrionnalValues;
|
||||
$product->list = $tmpList;
|
||||
if ($product->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.products.edit', $product)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['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)
|
||||
{
|
||||
if ($product->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.products.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
146
app/Http/Controllers/Bo/RangeController.php
Normal file
146
app/Http/Controllers/Bo/RangeController.php
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Ranges\StoreRangeRequest;
|
||||
use App\Http\Requests\Bo\Ranges\UpdateRangeRequest;
|
||||
use App\Models\Range;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RangeController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use HasPicture;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $range */
|
||||
$range = Range::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$range,
|
||||
$request->search,
|
||||
null,
|
||||
'label',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($range);
|
||||
$searchFields = trans('Label');
|
||||
|
||||
$rangeModels = $range->paginate(10);
|
||||
|
||||
return view('bo.pages.ranges.index', compact('rangeModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.pages.ranges.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Ranges\StoreRangeRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreRangeRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$range = new Range();
|
||||
$range->fill($request->validated());
|
||||
|
||||
if ($range->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.ranges.edit', $range)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Models\Range $range
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function edit(Range $range)
|
||||
{
|
||||
return view('bo.pages.ranges.edit', ['rangeModel' => $range]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Ranges\UpdateRangeRequest $request
|
||||
* @param \App\Models\Range $range
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateRangeRequest $request, Range $range)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $range) {
|
||||
$range->fill($request->validated());
|
||||
if ($range->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.ranges.edit', $range)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
} //end if
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Range $range
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Range $range)
|
||||
{
|
||||
if ($range->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.ranges.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
164
app/Http/Controllers/Bo/RecipeController.php
Normal file
164
app/Http/Controllers/Bo/RecipeController.php
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Recipes\StoreRecipeRequest;
|
||||
use App\Http\Requests\Bo\Recipes\UpdateRecipeRequest;
|
||||
use App\Models\Range;
|
||||
use App\Models\Recipe;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RecipeController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use HasPicture;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $recipe */
|
||||
$recipe = Recipe::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$recipe,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($recipe);
|
||||
$searchFields = trans('Nom');
|
||||
|
||||
$recipeModels = $recipe->paginate(10);
|
||||
|
||||
return view('bo.pages.recipes.index', compact('recipeModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$rangeModels = Range::orderBy('order', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.recipes.create', compact('rangeModels'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Recipes\StoreRecipeRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreRecipeRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$recipe = new Recipe();
|
||||
$tmpIngredients = \collect($request->validated()['ingredients'])->sortKeys();
|
||||
$recipe->fill($request->validated());
|
||||
$recipe->ingredients = $tmpIngredients;
|
||||
|
||||
if ($recipe->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.recipes.edit', $recipe)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.recipes'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.recipes'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Recipe $recipe
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Recipe $recipe)
|
||||
{
|
||||
$rangeModels = Range::orderBy('order', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.recipes.edit', [
|
||||
'recipeModel' => $recipe,
|
||||
'rangeModels' => $rangeModels
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Recipes\UpdateRecipeRequest $request
|
||||
* @param \App\Models\Recipe $recipe
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateRecipeRequest $request, Recipe $recipe)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $recipe) {
|
||||
$tmpIngredients = \collect($request->validated()['ingredients'])->sortKeys();
|
||||
$recipe->fill($request->validated());
|
||||
$recipe->ingredients = $tmpIngredients;
|
||||
|
||||
if ($recipe->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.recipes.edit', $recipe)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.recipes'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.recipes'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Recipe $recipe
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Recipe $recipe)
|
||||
{
|
||||
if ($recipe->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.recipes.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.recipes'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.recipes'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
153
app/Http/Controllers/Bo/SliderController.php
Normal file
153
app/Http/Controllers/Bo/SliderController.php
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Sliders\StoreSliderRequest;
|
||||
use App\Http\Requests\Bo\Sliders\UpdateSliderRequest;
|
||||
use App\Models\Slider;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SliderController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $sliders */
|
||||
$sliders = Slider::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$sliders,
|
||||
$request->search,
|
||||
null,
|
||||
'title',
|
||||
'subtitle',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($sliders);
|
||||
$searchFields = trans('Title, Subtitle');
|
||||
|
||||
$sliderModels = $sliders->paginate(10);
|
||||
|
||||
return view('bo.pages.sliders.index', compact('sliderModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.pages.sliders.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Sliders\StoreSliderRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreSliderRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$slider = new Slider();
|
||||
$slider->fill($request->validated());
|
||||
|
||||
if ($slider->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.sliders.edit', $slider)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.sliders'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.sliders'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Slider $slider
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Slider $slider)
|
||||
{
|
||||
return view('bo.pages.sliders.edit', [
|
||||
'sliderModel' => $slider
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Sliders\UpdateSliderRequest $request
|
||||
* @param \App\Models\Slider $slider
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateSliderRequest $request, Slider $slider)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $slider) {
|
||||
$slider->fill($request->validated());
|
||||
|
||||
if ($slider->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.sliders.edit', $slider)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.sliders'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.sliders'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Slider $slider
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Slider $slider)
|
||||
{
|
||||
if ($slider->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.sliders.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.sliders'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.sliders'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
162
app/Http/Controllers/Bo/StoreController.php
Normal file
162
app/Http/Controllers/Bo/StoreController.php
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Stores\StoreStoreRequest;
|
||||
use App\Http\Requests\Bo\Stores\UpdateStoreRequest;
|
||||
use App\Models\Store;
|
||||
use App\Models\StoreType;
|
||||
use App\Models\StoreRegion;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StoreController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use HasPicture;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $store */
|
||||
$store = Store::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$store,
|
||||
$request->search,
|
||||
null,
|
||||
'state',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($store);
|
||||
$searchFields = trans('State');
|
||||
|
||||
$storeModels = $store->paginate(10);
|
||||
|
||||
return view('bo.pages.stores.index', compact('storeModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$typeModels = StoreType::orderBy('name', 'ASC')->get();
|
||||
$regionModels = StoreRegion::orderBy('name', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.stores.create', compact('typeModels', 'regionModels'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Stores\StoreStoreRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreStoreRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$store = new Store();
|
||||
$store->fill($request->validated());
|
||||
|
||||
if ($store->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.stores.edit', $store)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.stores'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.stores'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Models\Store $store
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function edit(Store $store)
|
||||
{
|
||||
$typeModels = StoreType::orderBy('name', 'ASC')->get();
|
||||
$regionModels = StoreRegion::orderBy('name', 'ASC')->get();
|
||||
return view('bo.pages.stores.edit', [
|
||||
'storeModel' => $store,
|
||||
'typeModels' => $typeModels,
|
||||
'regionModels' => $regionModels
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Stores\UpdateStoreRequest $request
|
||||
* @param \App\Models\Store $store
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateStoreRequest $request, Store $store)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $store) {
|
||||
$store->fill($request->validated());
|
||||
if ($store->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.stores.edit', $store)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.stores'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.stores'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Store $store
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Store $store)
|
||||
{
|
||||
if ($store->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.stores.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.stores'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.stores'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
158
app/Http/Controllers/Bo/StoreGroupController.php
Normal file
158
app/Http/Controllers/Bo/StoreGroupController.php
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\StoreGroups\StoreStoreGroupRequest;
|
||||
use App\Http\Requests\Bo\StoreGroups\UpdateStoreGroupRequest;
|
||||
use App\Models\StoreGroup;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StoreGroupController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use HasPicture;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $storeGroup */
|
||||
$storeGroup = StoreGroup::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$storeGroup,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($storeGroup);
|
||||
$searchFields = trans('Name');
|
||||
|
||||
$storeGroupModels = $storeGroup->paginate(10);
|
||||
|
||||
return view('bo.pages.storegroups.index', compact('storeGroupModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.pages.storegroups.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StoreGroups\StoreStoreGroupRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreStoreGroupRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$storeGroup = new StoreGroup();
|
||||
$storeGroup->fill($request->validated());
|
||||
|
||||
if ($storeGroup->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storegroups.edit', $storeGroup)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.storegroups'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.storegroups'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Models\StoreGroup $storegroup
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function edit(StoreGroup $storegroup)
|
||||
{
|
||||
return view('bo.pages.storegroups.edit', ['storegroupModel' => $storegroup]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StoreGroups\UpdateStoreGroupRequest $request
|
||||
* @param \App\Models\StoreGroup $storegroup
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateStoreGroupRequest $request, StoreGroup $storegroup)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $storegroup) {
|
||||
$storegroup->fill($request->validated());
|
||||
if ($storegroup->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storegroups.edit', $storegroup)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.storegroups'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.storegroups'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\StoreGroup $storegroup
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(StoreGroup $storegroup)
|
||||
{
|
||||
foreach ($storegroup->storeRegions as $region) {
|
||||
foreach ($region->stores as $store) {
|
||||
$store->deleteOrFail();
|
||||
}
|
||||
$region->deleteOrFail();
|
||||
}
|
||||
|
||||
if ($storegroup->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storegroups.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.storegroups'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.storegroups'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
163
app/Http/Controllers/Bo/StoreRegionController.php
Normal file
163
app/Http/Controllers/Bo/StoreRegionController.php
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\StoreRegions\StoreStoreRegionRequest;
|
||||
use App\Http\Requests\Bo\StoreRegions\UpdateStoreRegionRequest;
|
||||
use App\Models\StoreRegion;
|
||||
use App\Models\StoreGroup;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StoreRegionController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use HasPicture;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $storeregion */
|
||||
$storeregion = StoreRegion::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$storeregion,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($storeregion);
|
||||
$searchFields = trans('Name');
|
||||
|
||||
$storeRegionModels = $storeregion->paginate(10);
|
||||
|
||||
return view('bo.pages.storeregions.index', compact('storeRegionModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$storegroupModels = StoreGroup::orderBy('order', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.storeregions.create', compact('storegroupModels'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StoreRegions\StoreStoreRegionRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreStoreRegionRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$storeregion = new StoreRegion();
|
||||
$storeregion->fill($request->validated());
|
||||
|
||||
if ($storeregion->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storeregions.edit', $storeregion)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.storeregions'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.storeregions'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\StoreRegion $storeregion
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(StoreRegion $storeregion)
|
||||
{
|
||||
$storegroupModels = StoreGroup::orderBy('order', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.storeregions.edit', [
|
||||
'storeregionModel' => $storeregion,
|
||||
'storegroupModels' => $storegroupModels
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StoreRegions\UpdateStoreRegionRequest $request
|
||||
* @param \App\Models\StoreRegion $storeregion
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateStoreRegionRequest $request, StoreRegion $storeregion)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $storeregion) {
|
||||
$storeregion->fill($request->validated());
|
||||
|
||||
if ($storeregion->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storeregions.edit', $storeregion)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.storeregions'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.storeregions'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\StoreRegion $storeregion
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(StoreRegion $storeregion)
|
||||
{
|
||||
foreach ($storeregion->stores as $store) {
|
||||
$store->deleteOrFail();
|
||||
}
|
||||
if ($storeregion->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storeregions.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.storeregions'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.storeregions'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
157
app/Http/Controllers/Bo/StoreTypeController.php
Normal file
157
app/Http/Controllers/Bo/StoreTypeController.php
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\StoreTypes\StoreStoreTypeRequest;
|
||||
use App\Http\Requests\Bo\StoreTypes\UpdateStoreTypeRequest;
|
||||
use App\Models\StoreType;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StoreTypeController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use HasPicture;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $storetype */
|
||||
$storetype = StoreType::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$storetype,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($storetype);
|
||||
$searchFields = trans('Name');
|
||||
|
||||
$storeTypeModels = $storetype->paginate(10);
|
||||
|
||||
return view('bo.pages.storetypes.index', compact('storeTypeModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.pages.storetypes.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StoreTypes\StoreStoreTypeRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreStoreTypeRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$storetype = new StoreType();
|
||||
$storetype->fill($request->validated());
|
||||
|
||||
if ($storetype->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storetypes.edit', $storetype)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.storetypes'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.storetypes'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\StoreType $storetype
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(StoreType $storetype)
|
||||
{
|
||||
return view('bo.pages.storetypes.edit', [
|
||||
'storetypeModel' => $storetype,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StoreTypes\UpdateStoreTypeRequest $request
|
||||
* @param \App\Models\StoreType $storetype
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateStoreTypeRequest $request, StoreType $storetype)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $storetype) {
|
||||
$storetype->fill($request->validated());
|
||||
|
||||
if ($storetype->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storetypes.edit', $storetype)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.storetypes'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.storetypes'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\StoreType $storetype
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(StoreType $storetype)
|
||||
{
|
||||
foreach ($storetype->stores as $store) {
|
||||
$store->deleteOrFail();
|
||||
}
|
||||
if ($storetype->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.storetypes.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.storetypes'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.storetypes'))]
|
||||
));
|
||||
}
|
||||
}
|
||||
125
app/Http/Controllers/Controller.php
Normal file
125
app/Http/Controllers/Controller.php
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
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\Schema;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
20
app/Http/Controllers/Fo/ConceptController.php
Normal file
20
app/Http/Controllers/Fo/ConceptController.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Concept;
|
||||
|
||||
class ConceptController extends Controller
|
||||
{
|
||||
/**
|
||||
* Page show
|
||||
*
|
||||
* @param \App\Models\Concept $concept
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function show(Concept $concept)
|
||||
{
|
||||
return view('fo.pages.concepts.concept', ['conceptModel' => $concept]);
|
||||
}
|
||||
}
|
||||
39
app/Http/Controllers/Fo/ContactController.php
Normal file
39
app/Http/Controllers/Fo/ContactController.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\ContactRequest;
|
||||
use App\Mail\ContactMessageReceived;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show contact page
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function contactForm()
|
||||
{
|
||||
return view('fo.pages.contact');
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit contact form
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\ContactRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function sendContactForm(ContactRequest $request)
|
||||
{
|
||||
Mail::queue(new ContactMessageReceived(
|
||||
first_name: $request->first_name,
|
||||
last_name: $request->last_name,
|
||||
email: $request->email,
|
||||
message: $request->message
|
||||
));
|
||||
|
||||
return redirect()->back()->with(['success' => \trans('Thank you for your message.')]);
|
||||
}
|
||||
}
|
||||
20
app/Http/Controllers/Fo/GroupController.php
Normal file
20
app/Http/Controllers/Fo/GroupController.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\StoreGroup;
|
||||
|
||||
class GroupController extends Controller
|
||||
{
|
||||
/**
|
||||
* RetailGroup Show
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \App\Models\StoreGroup
|
||||
*/
|
||||
public function show(int $id)
|
||||
{
|
||||
return StoreGroup::query()->find($id);
|
||||
}
|
||||
}
|
||||
22
app/Http/Controllers/Fo/HomeController.php
Normal file
22
app/Http/Controllers/Fo/HomeController.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Home;
|
||||
use App\Models\Slider;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$home = Home::query()->firstOrFail();
|
||||
$sliders = Slider::query()->where('status', true)->orderBy('order')->get();
|
||||
return view('fo.pages.home', compact('home', 'sliders'));
|
||||
}
|
||||
}
|
||||
37
app/Http/Controllers/Fo/ProductController.php
Normal file
37
app/Http/Controllers/Fo/ProductController.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Product;
|
||||
use App\Models\Range;
|
||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* Products index
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$ranges = Range::query()->where('status', true)
|
||||
->whereHas('products', fn (Builder $q) => $q->where('status', true))
|
||||
->with('products', fn (Builder $q) => $q->where('status', true)->orderBy('order'))
|
||||
->orderBy('order')
|
||||
->get();
|
||||
return view('fo.pages.products.index', compact(['ranges']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Product show
|
||||
*
|
||||
* @param \App\Models\Product $publishedProduct
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function show(Product $publishedProduct)
|
||||
{
|
||||
return view('fo.pages.products.show', ['productModel' => $publishedProduct]);
|
||||
}
|
||||
}
|
||||
35
app/Http/Controllers/Fo/RecipeController.php
Normal file
35
app/Http/Controllers/Fo/RecipeController.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Recipe;
|
||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||
|
||||
class RecipeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$recipes = Recipe::query()->where('status', true)
|
||||
->whereHas('range', fn (Builder $q) => $q->where('status', true))
|
||||
->orderBy('order')
|
||||
->get();
|
||||
return view('fo.pages.recipes.index', compact('recipes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Recipe show
|
||||
*
|
||||
* @param \App\Models\Recipe $publishedRecipe
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function show(Recipe $publishedRecipe)
|
||||
{
|
||||
return view('fo.pages.recipes.show', ['recipeModel' => $publishedRecipe]);
|
||||
}
|
||||
}
|
||||
20
app/Http/Controllers/Fo/RegionController.php
Normal file
20
app/Http/Controllers/Fo/RegionController.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\StoreRegion;
|
||||
|
||||
class RegionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show retail region
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \App\Models\StoreRegion;
|
||||
*/
|
||||
public function show(int $id)
|
||||
{
|
||||
return StoreRegion::find($id);
|
||||
}
|
||||
}
|
||||
27
app/Http/Controllers/Fo/StoreController.php
Normal file
27
app/Http/Controllers/Fo/StoreController.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\StoreFinderRequest;
|
||||
use App\Http\Resources\StoreFinderResource;
|
||||
use App\Models\Store;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class StoreController extends Controller
|
||||
{
|
||||
/**
|
||||
* Store by city
|
||||
*
|
||||
* @param \App\Http\Requests\Api\StoreFinderRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse;
|
||||
*/
|
||||
public function city(StoreFinderRequest $request): JsonResponse
|
||||
{
|
||||
return \response()->json(new StoreFinderResource(Store::query()
|
||||
->where('city', 'LIKE', '%' . $request->input('city') . '%')
|
||||
->orWhere('zipcode', 'LIKE', '%' . $request->input('city') . '%')
|
||||
->orderBy('order')
|
||||
->get()));
|
||||
}
|
||||
}
|
||||
93
app/Http/Kernel.php
Normal file
93
app/Http/Kernel.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?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' => [
|
||||
'htmlsanitize',
|
||||
\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,
|
||||
\CodeZero\LocalizedRoutes\Middleware\SetLocale::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\SecureHeaders::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware.
|
||||
*
|
||||
* These middleware may be assigned to groups or used individually.
|
||||
*
|
||||
* @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,
|
||||
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
|
||||
'lang' => \App\Http\Middleware\Lang::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The priority-sorted list of middleware.
|
||||
*
|
||||
* Forces non-global middleware to always be in the given order.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $middlewarePriority = [
|
||||
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
|
||||
\Illuminate\Cookie\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
|
||||
\Illuminate\Contracts\Session\Middleware\AuthenticatesSessions::class,
|
||||
\CodeZero\LocalizedRoutes\Middleware\SetLocale::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\Illuminate\Auth\Middleware\Authorize::class,
|
||||
];
|
||||
}
|
||||
40
app/Http/Middleware/Authenticate.php
Normal file
40
app/Http/Middleware/Authenticate.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
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
|
||||
{
|
||||
$logins = [
|
||||
'backend' => route('bo.login')
|
||||
];
|
||||
if (!$request->expectsJson()) {
|
||||
// * Notify must login
|
||||
Session::flash('warning', trans('Veuillez vous connecter pour continuer'));
|
||||
|
||||
foreach ($request->route()->gatherMiddleware() as $middleware) {
|
||||
if (\is_string($middleware) and strpos($middleware, 'auth:') !== false) {
|
||||
$route = $logins[str_replace('auth:', '', $middleware)] ?? null;
|
||||
if ($route) {
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
}
|
||||
return route('login');
|
||||
}
|
||||
abort(401);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
15
app/Http/Middleware/EncryptCookies.php
Normal file
15
app/Http/Middleware/EncryptCookies.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?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 = [];
|
||||
}
|
||||
61
app/Http/Middleware/HtmlSanitizer.php
Normal file
61
app/Http/Middleware/HtmlSanitizer.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class HtmlSanitizer
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|array ...$params
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next, string|array ...$params): Response
|
||||
{
|
||||
$inputs = $request->all();
|
||||
/** @var callable|null */
|
||||
$cleanInput = null;
|
||||
$cleanInput = function (
|
||||
null|string|array &$input,
|
||||
string $name,
|
||||
?string $rootName = null
|
||||
) use (
|
||||
$params,
|
||||
&$cleanInput
|
||||
): void {
|
||||
// * Nested element array
|
||||
if (is_array($input)) {
|
||||
array_walk_recursive($input, $cleanInput, $name);
|
||||
}
|
||||
if (!is_string($input)) {
|
||||
return;
|
||||
}
|
||||
if (in_array($name, $params) or in_array($rootName ?? $name, $params)) {
|
||||
// ? Is a json input ?
|
||||
if ($isJson = \json_decode($input, true) and is_array($isJson)) {
|
||||
// ! Decode each json field recursive.
|
||||
\array_walk_recursive($isJson, function (string|array &$item) {
|
||||
if (\is_string($item)) {
|
||||
$item = clean($item);
|
||||
$item = ToolboxHelper::stripCkEditorSchemesOnMediaInputs($item);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$input = clean($input);
|
||||
$input = ToolboxHelper::stripCkEditorSchemesOnMediaInputs($input);
|
||||
}
|
||||
} else {
|
||||
$input = strip_tags($input);
|
||||
}
|
||||
};
|
||||
\array_walk($inputs, $cleanInput);
|
||||
$request->merge($inputs);
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
30
app/Http/Middleware/Lang.php
Normal file
30
app/Http/Middleware/Lang.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class Lang
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
$prefix = Route::current()->action['prefix'];
|
||||
if ($prefix === '/bo') {
|
||||
app()->setLocale(session()->get('lang', config('app.locale')));
|
||||
return $next($request);
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
15
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
15
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?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 = [];
|
||||
}
|
||||
44
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
44
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
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|null ...$guards
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @throws \RuntimeException If guard is unhandled.
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next, ...$guards): Response
|
||||
{
|
||||
// phpcs:enable
|
||||
$guards = empty($guards) ? [null] : $guards;
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
if (Auth::guard($guard)->check()) {
|
||||
switch ($guard) {
|
||||
case 'frontend':
|
||||
return \redirect()->route('home');
|
||||
case 'backend':
|
||||
if (!$request->routeIs('bo.*')) {
|
||||
continue;
|
||||
}
|
||||
return \redirect()->route('bo.dashboard');
|
||||
default:
|
||||
throw new \RuntimeException("Unhandled guard `{$guard}` .");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
115
app/Http/Middleware/SecureHeaders.php
Normal file
115
app/Http/Middleware/SecureHeaders.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?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';",
|
||||
"prefetch-src 'self' https://cloud.ccm19.de;",
|
||||
// * CKEDITOR Specific https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/csp.html
|
||||
"connect-src 'self' blob: " . \implode(' ', [
|
||||
'https://rules.wo-gilt-was.de',
|
||||
'https://cloud.ccm19.de',
|
||||
'https://region1.google-analytics.com',
|
||||
'https://maps.googleapis.com',
|
||||
]) . ';',
|
||||
"img-src * data: blob:;",
|
||||
'frame-src ' . implode(' ', [
|
||||
'https://www.google.com/recaptcha/',
|
||||
'https://recaptcha.google.com/recaptcha/',
|
||||
'https://www.google.com/maps/'
|
||||
]) . ';',
|
||||
"font-src 'self' data: " . \implode(' ', [
|
||||
'https://fonts.gstatic.com',
|
||||
'https://use.typekit.net',
|
||||
]) . ';',
|
||||
// ! Using CKEditor will must have unsafe-inline style
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
"style-src 'self' 'unsafe-inline' " . \implode(' ', [
|
||||
'https://cdnjs.cloudflare.com',
|
||||
'https://use.typekit.net',
|
||||
'https://p.typekit.net',
|
||||
'https://cloud.ccm19.de',
|
||||
// * 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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
15
app/Http/Middleware/ValidateSignature.php
Normal file
15
app/Http/Middleware/ValidateSignature.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?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>
|
||||
*/
|
||||
protected $except = [];
|
||||
}
|
||||
17
app/Http/Middleware/VerifyCsrfToken.php
Normal file
17
app/Http/Middleware/VerifyCsrfToken.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?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 = [
|
||||
'/csp-report', '/*'
|
||||
];
|
||||
}
|
||||
30
app/Http/Requests/Api/StoreFinderRequest.php
Normal file
30
app/Http/Requests/Api/StoreFinderRequest.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Api;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreFinderRequest 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 [
|
||||
'city' => 'required|string|min:1'
|
||||
];
|
||||
}
|
||||
}
|
||||
43
app/Http/Requests/Bo/ChangeOrderRequest.php
Normal file
43
app/Http/Requests/Bo/ChangeOrderRequest.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ChangeOrderRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'direction' => $this->action === 'up' ? true : false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'action' => 'required|string|in:up,down',
|
||||
'direction' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
}
|
||||
89
app/Http/Requests/Bo/Concepts/StoreConceptRequest.php
Normal file
89
app/Http/Requests/Bo/Concepts/StoreConceptRequest.php
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Concepts;
|
||||
|
||||
use App\Http\Requests\Bo\UpdateMiniCrudRequest;
|
||||
use App\Models\Concept;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StoreConceptRequest extends UpdateMiniCrudRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return (auth('backend')->check() && Concept::count() < 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'slug' => Str::slug(strip_tags($this->name))
|
||||
]);
|
||||
$this->mergePicture('picture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'seo_title' => 'required|min:3|max:70',
|
||||
'seo_description' => 'required|min:50|max:160',
|
||||
|
||||
'name' => 'required|min:3|max:70',
|
||||
'slug' => 'unique_translation:concepts',
|
||||
'title' => 'required|min:3|max:70',
|
||||
'subtitle' => 'required|min:3|max:70',
|
||||
'description' => 'required|string|min:15',
|
||||
'data' => 'present|array',
|
||||
'data.*' => 'required|array',
|
||||
|
||||
'picture_alt' => 'required|min:3|max:255',
|
||||
'picture_title' => 'required|min:3|max:255',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 1512, 354, 1512, 354, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'seo_title' => trans('titre') . ' seo',
|
||||
'seo_description' => trans('description') . ' seo',
|
||||
|
||||
'name' => trans('name of the concept'),
|
||||
'slug' => trans('slug of the concept'),
|
||||
'title' => trans('title of the concept'),
|
||||
'subtitle' => trans('subtitle of the concept'),
|
||||
'description' => trans('description of the concept'),
|
||||
'data' => trans('values of the data'),
|
||||
'data.*.value' => trans('value of the data'),
|
||||
|
||||
'picture' => trans('illustration'),
|
||||
'picture_alt' => trans('alt attribute of the image'),
|
||||
'picture_title' => trans('title attribute of the image'),
|
||||
];
|
||||
}
|
||||
}
|
||||
26
app/Http/Requests/Bo/Concepts/UpdateConceptRequest.php
Normal file
26
app/Http/Requests/Bo/Concepts/UpdateConceptRequest.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Concepts;
|
||||
|
||||
use App\Http\Requests\Bo\Concepts\StoreConceptRequest;
|
||||
use CodeZero\UniqueTranslation\UniqueTranslationRule;
|
||||
|
||||
class UpdateConceptRequest extends StoreConceptRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'slug' => UniqueTranslationRule::for('concepts')->ignore($this->concept->id),
|
||||
];
|
||||
return \array_merge(
|
||||
parent::rules(),
|
||||
$rules,
|
||||
$this->pictureRules('picture', 1512, 354, 1512, 354, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
97
app/Http/Requests/Bo/Homes/UpdateHomeRequest.php
Normal file
97
app/Http/Requests/Bo/Homes/UpdateHomeRequest.php
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Homes;
|
||||
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateHomeRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->mergePicture('part3_picture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'seo_title' => 'required|min:3|max:70',
|
||||
'seo_description' => 'required|min:50|max:160',
|
||||
|
||||
'part1_title' => 'required|min:3|max:70',
|
||||
'part1_subtitle' => 'required|min:3|max:70',
|
||||
'part1_text_1' => 'required|string|min:15',
|
||||
'part1_text_2' => 'required|string|min:15',
|
||||
'part1_text_3' => 'required|string|min:15',
|
||||
|
||||
'part2_title' => 'required|min:3|max:70',
|
||||
'part2_subtitle' => 'required|min:3|max:70',
|
||||
'part2_text' => 'required|string|min:15',
|
||||
'part2_list' => 'present|array',
|
||||
'part2_list.*' => 'required|array',
|
||||
'part2_list.*.value' => 'required|string|min:3|max:255',
|
||||
'part2_product1_id' => 'required|exists:products,id',
|
||||
'part2_product2_id' => 'required|exists:products,id',
|
||||
|
||||
'part3_picture_alt' => 'required|min:3|max:255',
|
||||
'part3_picture_title' => 'required|min:3|max:255',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('part3_picture', 2048, 1366, 2048, 1366, true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'seo_title' => trans('titre') . ' seo',
|
||||
'seo_description' => trans('description') . ' seo',
|
||||
|
||||
'part1_title' => trans('title part.1'),
|
||||
'part1_subtitle' => trans('subtitle part.1'),
|
||||
'part1_text_1' => trans('text 1 part.1'),
|
||||
'part1_text_2' => trans('text 2 part.1'),
|
||||
'part1_text_3' => trans('text 3 part.1'),
|
||||
|
||||
'part2_title' => trans('title part.2'),
|
||||
'part2_subtitle' => trans('subtitle part.2'),
|
||||
'part2_text' => trans('text part.2'),
|
||||
'part2_list' => trans('values of the list part.2'),
|
||||
'part2_list.*.value' => trans('value of the list part.2'),
|
||||
'part2_product1_id' => trans('value of the first product part.2'),
|
||||
'part2_product2_id' => trans('value of the second product part.2'),
|
||||
|
||||
'part3_picture' => trans('illustration'),
|
||||
'part3_picture_alt' => trans('alt attribute of the image'),
|
||||
'part3_picture_title' => trans('title attribute of the image'),
|
||||
];
|
||||
}
|
||||
}
|
||||
112
app/Http/Requests/Bo/Products/StoreProductRequest.php
Normal file
112
app/Http/Requests/Bo/Products/StoreProductRequest.php
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Products;
|
||||
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StoreProductRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'slug' => Str::slug(strip_tags($this->label)),
|
||||
'status' => $this->status ? true : false,
|
||||
'list' => $this->list ?? [],
|
||||
'nutritionnal_values' => $this->nutritionnal_values ?? [],
|
||||
'certifications' => \collect($this->certifications)->all(),
|
||||
]);
|
||||
$this->mergePicture('picture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'seo_title' => 'required|min:3|max:70',
|
||||
'seo_description' => 'required|min:50|max:160',
|
||||
'label' => 'required|min:3|max:255',
|
||||
'slug' => 'unique_translation:products',
|
||||
'description' => 'required|string|min:15',
|
||||
'picture_alt' => 'required|min:3|max:255',
|
||||
'picture_title' => 'required|min:3|max:255',
|
||||
'certifications' => 'present|array',
|
||||
'certifications.*' => 'required|integer',
|
||||
'list' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (1 > count($value)) {
|
||||
$fail(\trans('You must fill in at least 2 lines in the list.'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'list.*' => 'required|array',
|
||||
'list.*.value' => 'nullable|string|min:3|max:255',
|
||||
'nutritionnal_values' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (1 > count($value)) {
|
||||
$fail(\trans('You must fill in at least 2 lines of nutritional values.'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'nutritionnal_values.*' => 'required|array',
|
||||
'nutritionnal_values.*.label' => 'nullable|string|min:3|max:255',
|
||||
'nutritionnal_values.*.value' => 'nullable|string|min:3|max:255',
|
||||
'range_id' => 'required|exists:ranges,id',
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 600, 600, 600, 600, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'seo_title' => trans('title') . ' seo',
|
||||
'seo_description' => trans('description') . ' seo',
|
||||
'label' => trans('label'),
|
||||
'slug' => trans('slug'),
|
||||
'description' => trans('description'),
|
||||
'picture_alt' => trans('picture_alt'),
|
||||
'picture_title' => trans('picture_title'),
|
||||
'certifications' => trans('certifications'),
|
||||
'certifications.*' => trans('value(s) of certifications'),
|
||||
'list' => trans('list'),
|
||||
'nutritionnal_values' => trans('nutritionnal_values'),
|
||||
'nutritionnal_values.*.label' => trans('label(s) of nutritionnal_values'),
|
||||
'nutritionnal_values.*.value' => trans('value(s) of nutritionnal_values'),
|
||||
'range_id' => trans('range'),
|
||||
'status' => trans('publish'),
|
||||
];
|
||||
}
|
||||
}
|
||||
55
app/Http/Requests/Bo/Products/UpdateProductRequest.php
Normal file
55
app/Http/Requests/Bo/Products/UpdateProductRequest.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Products;
|
||||
|
||||
use CodeZero\UniqueTranslation\UniqueTranslationRule;
|
||||
|
||||
class UpdateProductRequest extends StoreProductRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'seo_title' => 'required|min:3|max:70',
|
||||
'seo_description' => 'required|min:50|max:160',
|
||||
'label' => 'required|min:3|max:255',
|
||||
'slug' => UniqueTranslationRule::for('products')->ignore($this->product->id),
|
||||
'description' => 'required|string|min:15',
|
||||
'picture_alt' => 'required|min:3|max:255',
|
||||
'picture_title' => 'required|min:3|max:255',
|
||||
'certifications' => 'present|array',
|
||||
'certifications.*' => 'required|integer',
|
||||
'list' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (1 > count($value)) {
|
||||
$fail(\trans('You must fill in at least 2 lines in the list.'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'list.*' => 'required|array',
|
||||
'list.*.value' => 'nullable|string|min:3|max:255',
|
||||
'nutritionnal_values' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (1 > count($value)) {
|
||||
$fail(\trans('You must fill in at least 2 lines of nutritional values.'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'nutritionnal_values.*' => 'required|array',
|
||||
'nutritionnal_values.*.label' => 'nullable|string|min:3|max:255',
|
||||
'nutritionnal_values.*.value' => 'nullable|string|min:3|max:255',
|
||||
'range_id' => 'required|exists:ranges,id',
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 600, 600, 600, 600, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
71
app/Http/Requests/Bo/Ranges/StoreRangeRequest.php
Normal file
71
app/Http/Requests/Bo/Ranges/StoreRangeRequest.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Ranges;
|
||||
|
||||
use App\Enums\Ranges\PictoEnum;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class StoreRangeRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'slug' => Str::slug(strip_tags($this->label)),
|
||||
'status' => $this->status ? true : false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'seo_title' => 'required|min:3|max:70',
|
||||
'seo_description' => 'required|min:50|max:160',
|
||||
'label' => 'required|min:3|max:255',
|
||||
'slug' => 'unique_translation:ranges',
|
||||
'picto' => [new Enum(PictoEnum::class)],
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'seo_title' => trans('title') . ' seo',
|
||||
'seo_description' => trans('description') . ' seo',
|
||||
'label' => trans('label'),
|
||||
'picto' => trans('picto'),
|
||||
'slug' => trans('slug'),
|
||||
'status' => trans('publish')
|
||||
];
|
||||
}
|
||||
}
|
||||
27
app/Http/Requests/Bo/Ranges/UpdateRangeRequest.php
Normal file
27
app/Http/Requests/Bo/Ranges/UpdateRangeRequest.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Ranges;
|
||||
|
||||
use App\Enums\Ranges\PictoEnum;
|
||||
use CodeZero\UniqueTranslation\UniqueTranslationRule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class UpdateRangeRequest extends StoreRangeRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'seo_title' => 'required|min:3|max:70',
|
||||
'seo_description' => 'required|min:50|max:160',
|
||||
'label' => 'required|min:3|max:255',
|
||||
'slug' => UniqueTranslationRule::for('ranges')->ignore($this->range->id),
|
||||
'picto' => [new Enum(PictoEnum::class)],
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
}
|
||||
}
|
||||
107
app/Http/Requests/Bo/Recipes/StoreRecipeRequest.php
Normal file
107
app/Http/Requests/Bo/Recipes/StoreRecipeRequest.php
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Recipes;
|
||||
|
||||
use App\Enums\Recipes\DifficultyEnum;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class StoreRecipeRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'slug' => Str::slug(strip_tags($this->name)),
|
||||
'status' => $this->status ? true : false,
|
||||
]);
|
||||
$this->mergePicture('picture');
|
||||
$this->mergePicture('picture_thumbnail');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'seo_title' => 'required|min:3|max:70',
|
||||
'seo_description' => 'required|min:50|max:160',
|
||||
'name' => 'required|min:3|max:255',
|
||||
'slug' => 'unique_translation:recipes',
|
||||
'picture_alt' => 'required|min:3|max:255',
|
||||
'picture_title' => 'required|min:3|max:255',
|
||||
'picture_thumbnail_alt' => 'required|min:3|max:255',
|
||||
'picture_thumbnail_title' => 'required|min:3|max:255',
|
||||
'ingredients' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (1 > count($value)) {
|
||||
$fail(\trans('You must fill in at least 1 line of ingredients.'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'ingredients.*' => 'nullable|array',
|
||||
'ingredients.*.header' => 'nullable|string|min:3|max:255',
|
||||
'ingredients.*.value' => 'string|min:3|max:255',
|
||||
'teaser' => 'required|min:50|max:160',
|
||||
'steps' => 'required|string|min:15',
|
||||
'difficulty' => [new Enum(DifficultyEnum::class)],
|
||||
'duration' => 'required|string|min:1|max:150',
|
||||
'tips' => 'required|string|min:15',
|
||||
'range_id' => 'required|exists:ranges,id',
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 1600, 900, 1600, 900, false),
|
||||
$this->pictureRules('picture_thumbnail', 430, 242, 430, 242, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'seo_title' => trans('title') . ' seo',
|
||||
'seo_description' => trans('description') . ' seo',
|
||||
'name' => trans('name'),
|
||||
'slug' => trans('slug'),
|
||||
'ingredients' => trans('ingredients'),
|
||||
'ingredients.*.header' => trans('header in the list of ingredients'),
|
||||
'ingredients.*.label' => trans('value of ingredients'),
|
||||
'ingredients.*.value' => trans('value of ingredients'),
|
||||
'teaser' => trans('teaser'),
|
||||
'steps' => trans('steps'),
|
||||
'difficulty' => trans('difficulty'),
|
||||
'duration' => trans('duration'),
|
||||
'tips' => trans('tips'),
|
||||
'range_id' => trans('range'),
|
||||
'status' => trans('publish')
|
||||
];
|
||||
}
|
||||
}
|
||||
26
app/Http/Requests/Bo/Recipes/UpdateRecipeRequest.php
Normal file
26
app/Http/Requests/Bo/Recipes/UpdateRecipeRequest.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Recipes;
|
||||
|
||||
use CodeZero\UniqueTranslation\UniqueTranslationRule;
|
||||
|
||||
class UpdateRecipeRequest extends StoreRecipeRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'slug' => UniqueTranslationRule::for('recipes')->ignore($this->recipe->id)
|
||||
];
|
||||
return \array_merge(
|
||||
parent::rules(),
|
||||
$rules,
|
||||
$this->pictureRules('picture', 1600, 900, 1600, 900, true),
|
||||
$this->pictureRules('picture_thumbnail', 430, 242, 430, 242, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
88
app/Http/Requests/Bo/Sliders/StoreSliderRequest.php
Normal file
88
app/Http/Requests/Bo/Sliders/StoreSliderRequest.php
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Sliders;
|
||||
|
||||
use App\Enums\Sliders\TypeEnum;
|
||||
use App\Http\Requests\Bo\UpdateMiniCrudRequest;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class StoreSliderRequest extends UpdateMiniCrudRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'link_new_tab' => $this->link_new_tab ? true : false,
|
||||
'status' => $this->status ? true : false,
|
||||
'publish_at' => $this->publish_at ? \str_replace('T', ' ', $this->publish_at) : null,
|
||||
'unpublish_at' => $this->unpublish_at ? \str_replace('T', ' ', $this->unpublish_at) : null,
|
||||
]);
|
||||
$this->mergePicture('picture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'type' => [new Enum(TypeEnum::class)],
|
||||
'title' => 'required|min:3|max:70',
|
||||
'subtitle' => 'required|min:3|max:70',
|
||||
'description' => 'required|string|min:15',
|
||||
'link' => 'required|url',
|
||||
'link_title' => 'required|min:3|max:255',
|
||||
'link_new_tab' => 'required|boolean',
|
||||
'picture_alt' => 'required|min:3|max:255',
|
||||
'picture_title' => 'required|min:3|max:255',
|
||||
'status' => 'required|boolean',
|
||||
'publish_at' => 'sometimes|nullable|date',
|
||||
'unpublish_at' => 'sometimes|nullable|date'
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 1270, 930, 1270, 930, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'type' => trans('type of slider'),
|
||||
'title' => trans('title of the slide'),
|
||||
'subtitle' => trans('subtitle of the slide'),
|
||||
'description' => trans('description of the slide'),
|
||||
'link' => trans('link of the slide'),
|
||||
'link_title' => trans('title of link'),
|
||||
'link_new_tab' => trans('open the link in the new tab'),
|
||||
'picture' => trans('illustration'),
|
||||
'picture_alt' => trans('alt attribute of the image'),
|
||||
'picture_title' => trans('title attribute of the image'),
|
||||
'status' => trans('status of the slide'),
|
||||
];
|
||||
}
|
||||
}
|
||||
9
app/Http/Requests/Bo/Sliders/UpdateSliderRequest.php
Normal file
9
app/Http/Requests/Bo/Sliders/UpdateSliderRequest.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Sliders;
|
||||
|
||||
use App\Http\Requests\Bo\Sliders\StoreSliderRequest;
|
||||
|
||||
class UpdateSliderRequest extends StoreSliderRequest
|
||||
{
|
||||
}
|
||||
59
app/Http/Requests/Bo/StoreGroups/StoreStoreGroupRequest.php
Normal file
59
app/Http/Requests/Bo/StoreGroups/StoreStoreGroupRequest.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\StoreGroups;
|
||||
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreStoreGroupRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->mergePicture('picture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|min:3|max:255',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 200, 200, 600, 600, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'name' => trans('name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
30
app/Http/Requests/Bo/StoreGroups/UpdateStoreGroupRequest.php
Normal file
30
app/Http/Requests/Bo/StoreGroups/UpdateStoreGroupRequest.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\StoreGroups;
|
||||
|
||||
use App\Http\Requests\Bo\StoreGroups\StoreStoreGroupRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class UpdateStoreGroupRequest extends StoreStoreGroupRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => [
|
||||
'required',
|
||||
'min:3',
|
||||
'max:255',
|
||||
Rule::unique('store_groups', 'name')->ignore($this->storegroup)
|
||||
],
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 200, 200, 600, 600, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\StoreRegions;
|
||||
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreStoreRegionRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->mergePicture('picture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|min:3|max:255',
|
||||
'group_id' => 'required|exists:store_groups,id',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 200, 200, 600, 600, true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'name' => trans('name'),
|
||||
'group_id' => trans('group'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\StoreRegions;
|
||||
|
||||
use App\Http\Requests\Bo\StoreRegions\StoreStoreRegionRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class UpdateStoreRegionRequest extends StoreStoreRegionRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => [
|
||||
'required',
|
||||
'min:3',
|
||||
'max:255',
|
||||
Rule::unique('store_regions', 'name')->ignore($this->storeregion)
|
||||
],
|
||||
'group_id' => 'required|exists:store_groups,id',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 200, 200, 600, 600, false),
|
||||
);
|
||||
}
|
||||
}
|
||||
45
app/Http/Requests/Bo/StoreTypes/StoreStoreTypeRequest.php
Normal file
45
app/Http/Requests/Bo/StoreTypes/StoreStoreTypeRequest.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\StoreTypes;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreStoreTypeRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|min:3|max:255',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'name' => trans('name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
29
app/Http/Requests/Bo/StoreTypes/UpdateStoreTypeRequest.php
Normal file
29
app/Http/Requests/Bo/StoreTypes/UpdateStoreTypeRequest.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\StoreTypes;
|
||||
|
||||
use App\Http\Requests\Bo\StoreTypes\StoreStoreTypeRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class UpdateStoreTypeRequest extends StoreStoreTypeRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => [
|
||||
'required',
|
||||
'min:3',
|
||||
'max:255',
|
||||
Rule::unique('store_types', 'name')->ignore($this->storetype)
|
||||
],
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
);
|
||||
}
|
||||
}
|
||||
62
app/Http/Requests/Bo/Stores/StoreStoreRequest.php
Normal file
62
app/Http/Requests/Bo/Stores/StoreStoreRequest.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Stores;
|
||||
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreStoreRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'state' => 'required|min:3|max:255',
|
||||
'type_id' => 'required|exists:store_types,id',
|
||||
'street' => 'required|min:3|max:255',
|
||||
'zipcode' => 'required|min:0|max:5',
|
||||
'city' => 'required|min:3|max:255',
|
||||
'latitude' => 'required|between:-90,90|decimal:0,8',
|
||||
'longitude' => 'required|between:-180,180|decimal:0,8',
|
||||
'region_id' => 'required|exists:store_regions,id',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'state' => trans('State'),
|
||||
'type_id' => trans('Type'),
|
||||
'street' => trans('Street'),
|
||||
'zipcode' => trans('Zipcode'),
|
||||
'city' => trans('City'),
|
||||
'latitude' => trans('Latitude'),
|
||||
'longitude' => trans('Longitude'),
|
||||
'region_id' => trans('Region'),
|
||||
];
|
||||
}
|
||||
}
|
||||
9
app/Http/Requests/Bo/Stores/UpdateStoreRequest.php
Normal file
9
app/Http/Requests/Bo/Stores/UpdateStoreRequest.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Stores;
|
||||
|
||||
use App\Http\Requests\Bo\Stores\StoreStoreRequest;
|
||||
|
||||
class UpdateStoreRequest extends StoreStoreRequest
|
||||
{
|
||||
}
|
||||
156
app/Http/Requests/Bo/UpdateMiniCrudRequest.php
Normal file
156
app/Http/Requests/Bo/UpdateMiniCrudRequest.php
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use App\Enums\InputType;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
abstract class UpdateMiniCrudRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* The model parameter name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $modelName = null;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
* @phpcs:disable Generic.Metrics.NestingLevel.TooHigh
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
// phpcs:enable
|
||||
$rules = [];
|
||||
foreach ($this->{$this->modelName}->data as $iptName => $input) {
|
||||
$input = \json_decode(\json_encode($input), true);
|
||||
switch ($input['inputType']) {
|
||||
case InputType::number->value:
|
||||
$rules = array_merge($rules, [
|
||||
"data.$iptName.value" => $this->compileValidate('required|numeric', $input)
|
||||
]);
|
||||
break;
|
||||
case InputType::string->value:
|
||||
$rules = array_merge($rules, [
|
||||
"data.$iptName.value" => $this->compileValidate('required|string|min:3', $input)
|
||||
]);
|
||||
break;
|
||||
case InputType::text->value:
|
||||
$mergeRules = $this->compileValidate('required|string|min:15', $input);
|
||||
$mergeRules = collect(\explode('|', $mergeRules))
|
||||
->map(function ($rule) {
|
||||
if (\strpos($rule, 'max:') !== false) {
|
||||
$max = \intval(str_replace('max:', '', $rule));
|
||||
return function ($attribute, $value, $fail) use ($max) {
|
||||
if (\strlen(\strip_tags($value)) > $max) {
|
||||
$fail("$attribute ne doit pas excéder $max caractères");
|
||||
}
|
||||
};
|
||||
}
|
||||
return $rule;
|
||||
});
|
||||
$rules = array_merge($rules, [
|
||||
"data.$iptName.text" => $mergeRules
|
||||
]);
|
||||
break;
|
||||
case InputType::image->value:
|
||||
$ipt = $this->data[$iptName];
|
||||
$max = isset($ipt['dimensionsMax']);
|
||||
$dim = collect(explode(
|
||||
',',
|
||||
$ipt['dimensionsMax'] ?? $input['dimensions']
|
||||
))->mapWithKeys(function ($v) {
|
||||
$v = explode(' ', $v);
|
||||
return [$v[0] => $v[1]];
|
||||
});
|
||||
$rules = array_merge($rules, [
|
||||
"data.$iptName.value" => $this->compileValidate(
|
||||
implode('|', [
|
||||
'required',
|
||||
'image',
|
||||
'mimes:png,jpg,jpeg',
|
||||
sprintf(
|
||||
'dimensions:%s=%d,%s=%d',
|
||||
$max ? 'max_height' : 'height',
|
||||
$dim['hauteur'],
|
||||
$max ? 'max_width' : 'width',
|
||||
$dim['largeur']
|
||||
)
|
||||
]),
|
||||
$input
|
||||
),
|
||||
"data.$iptName.alt" => $this->compileValidate('required|string|min:5', $input),
|
||||
"data.$iptName.title" => $this->compileValidate('required|string|min:5', $input)
|
||||
]);
|
||||
break;
|
||||
case InputType::url->value:
|
||||
$rules = array_merge($rules, [
|
||||
"data.$iptName.value" => [
|
||||
'required', 'url',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
try {
|
||||
ToolboxHelper::assertNoInternalUrls($attribute, $value);
|
||||
ToolboxHelper::assertNoInternalBoUrls($attribute, $value);
|
||||
} catch (ValidationException $e) {
|
||||
$fail(collect($e->errors())->first()[0]);
|
||||
}
|
||||
}
|
||||
]
|
||||
]);
|
||||
break;
|
||||
case InputType::boolean->value:
|
||||
$all = $this->all();
|
||||
$nested = ToolboxHelper::dotStringToNestedArray(
|
||||
"data.$iptName.value",
|
||||
$this->input("data.$iptName.value") ? true : false
|
||||
);
|
||||
$all = array_merge_recursive_distinct($all, $nested);
|
||||
$this->merge($all);
|
||||
$rules = array_merge($rules, [
|
||||
"data.$iptName.value" => 'boolean'
|
||||
]);
|
||||
break;
|
||||
} //end switch
|
||||
} //end foreach
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param string $inputTypeValidate
|
||||
* @param array $input
|
||||
* @return string
|
||||
*/
|
||||
public function compileValidate(string $inputTypeValidate, array $input): string
|
||||
{
|
||||
if (!isset($input['validate']) or !\is_string($input['validate'])) {
|
||||
return $inputTypeValidate;
|
||||
}
|
||||
/** @var array */
|
||||
$inputValidate = explode('|', $input['validate']);
|
||||
$out = explode('|', $inputTypeValidate);
|
||||
foreach ($inputValidate as $validate) {
|
||||
if (!\in_array($validate, $out)) {
|
||||
$out[] = $validate;
|
||||
}
|
||||
}
|
||||
return \implode('|', $out);
|
||||
}
|
||||
}
|
||||
46
app/Http/Requests/Fo/ContactRequest.php
Normal file
46
app/Http/Requests/Fo/ContactRequest.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Fo;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ContactRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'terms' => $this->terms ? true : false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'first_name' => 'required|min:1',
|
||||
'last_name' => 'required|min:1',
|
||||
'email' => 'required|email:rfc,spoof,dns,strict',
|
||||
'message' => 'required|string|min:10',
|
||||
'terms' => 'accepted',
|
||||
];
|
||||
}
|
||||
}
|
||||
30
app/Http/Requests/ProductIndexFilterRequest.php
Normal file
30
app/Http/Requests/ProductIndexFilterRequest.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ProductIndexFilterRequest 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 [
|
||||
'range_id' => 'sometimes|nullable|exists:ranges,id'
|
||||
];
|
||||
}
|
||||
}
|
||||
32
app/Http/Resources/StoreFinderResource.php
Normal file
32
app/Http/Resources/StoreFinderResource.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Models\Store;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class StoreFinderResource extends ResourceCollection
|
||||
{
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array<int|string, mixed>
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
// phpcs:enable
|
||||
return $this->collection->map(fn (Store $store) => [
|
||||
'name' => $store->storeRegion->storeGroup->name,
|
||||
'type' => $store->storeType->name,
|
||||
'street' => $store->street,
|
||||
'zipcode' => $store->zipcode,
|
||||
'city' => $store->city,
|
||||
'latitude' => $store->latitude,
|
||||
'longitude' => $store->longitude,
|
||||
'picture' => $store->storeRegion->storeGroup->picture,
|
||||
])->all();
|
||||
}
|
||||
}
|
||||
41
app/Jobs/SlidersStatusUpdate.php
Normal file
41
app/Jobs/SlidersStatusUpdate.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Slider;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Update published and visibility attributes reading their
|
||||
* publish_at and unpublish_at attributes.
|
||||
*/
|
||||
class SlidersStatusUpdate
|
||||
{
|
||||
/**
|
||||
* Called when the job will be executed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$slidersToPublish = Slider::where('publish_at', '<=', Carbon::now()->toDateTime())
|
||||
->whereNotNull('publish_at')
|
||||
->where('status', false)->get();
|
||||
Log::debug(__CLASS__ . " sliders to publish " . $slidersToPublish->count());
|
||||
foreach ($slidersToPublish as $slider) {
|
||||
$slider->publish_at = null;
|
||||
$slider->status = true;
|
||||
$slider->saveOrFail();
|
||||
}
|
||||
$slidersToUnPublish = Slider::where('unpublish_at', '<=', Carbon::now()->toDateTime())
|
||||
->whereNotNull('unpublish_at')
|
||||
->where('status', true)->get();
|
||||
Log::debug(__CLASS__ . " sliders to unpublish " . $slidersToPublish->count());
|
||||
foreach ($slidersToUnPublish as $slider) {
|
||||
$slider->unpublish_at = null;
|
||||
$slider->status = false;
|
||||
$slider->saveOrFail();
|
||||
}
|
||||
}
|
||||
}
|
||||
190
app/Lib/Helpers/ExceptionsHelper.php
Normal file
190
app/Lib/Helpers/ExceptionsHelper.php
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Helpers;
|
||||
|
||||
class ExceptionsHelper
|
||||
{
|
||||
/**
|
||||
* Handle sentry event
|
||||
*
|
||||
* @param \Sentry\Event $event
|
||||
* @return null|\Sentry\Event
|
||||
*/
|
||||
public static function sentryEventHandler(\Sentry\Event $event): ?\Sentry\Event
|
||||
{
|
||||
// Remove unwanted reports.
|
||||
$event->setModules([]);
|
||||
$event->setOsContext(null);
|
||||
|
||||
/** @var \Sentry\ExceptionDataBag[] */
|
||||
$exceptionBag = [];
|
||||
foreach ($event->getExceptions() as $exceptionDataBag) {
|
||||
$exceptionBag[] = self::getAnonymizedSentryException($exceptionDataBag);
|
||||
}
|
||||
$event->setExceptions($exceptionBag);
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonimize Sentry Exception bag
|
||||
*
|
||||
* @param \Sentry\ExceptionDataBag $exceptionDataBag
|
||||
* @return \Sentry\ExceptionDataBag
|
||||
*/
|
||||
private static function getAnonymizedSentryException(
|
||||
\Sentry\ExceptionDataBag $exceptionDataBag
|
||||
): \Sentry\ExceptionDataBag {
|
||||
$exceptionDataBag->setValue(self::getAnonymizedMessage($exceptionDataBag->getValue()));
|
||||
if ($stackTrace = $exceptionDataBag->getStacktrace()) {
|
||||
$exceptionDataBag->setStacktrace(self::getAnonymizedSentryStackTrace($stackTrace));
|
||||
}
|
||||
return $exceptionDataBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymise sentry stacktrace
|
||||
*
|
||||
* @param \Sentry\Stacktrace $stackTrace
|
||||
* @return \Sentry\Stacktrace
|
||||
*/
|
||||
private static function getAnonymizedSentryStackTrace(\Sentry\Stacktrace $stackTrace): \Sentry\Stacktrace
|
||||
{
|
||||
/** @var \Sentry\Frame[] */
|
||||
$frames = \array_reverse($stackTrace->getFrames(), true);
|
||||
$i = \count($frames) - 1;
|
||||
// * Remove all but keep first (index.php).
|
||||
while ($i-- > 0) {
|
||||
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||
}
|
||||
foreach ($frames as $index => $frame) {
|
||||
$frame->setPostContext([]);
|
||||
$frame->setPreContext([]);
|
||||
$frame->setContextLine('');
|
||||
$frame->setVars(self::getAnonymizedSentryParams($frame->getVars()));
|
||||
$stackTrace->addFrame($frame);
|
||||
if ($index === 0) {
|
||||
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||
}
|
||||
}
|
||||
return $stackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get anonymized sentry params
|
||||
*
|
||||
* @param mixed[] $params
|
||||
* @return string[]
|
||||
*/
|
||||
private static function getAnonymizedSentryParams(array $params): array
|
||||
{
|
||||
foreach ($params as &$param) {
|
||||
$type = \strtolower(\gettype($param));
|
||||
if (\is_string($param)) {
|
||||
$type = \explode(' ', \trim(strtolower($param)))[0] ?? null;
|
||||
}
|
||||
switch (true) {
|
||||
case $type === 'lambda':
|
||||
case $type === 'object':
|
||||
continue 2;
|
||||
case $type === 'array' and \is_array($param):
|
||||
$param = sprintf('Array(%d)', \count($param));
|
||||
continue 2;
|
||||
default:
|
||||
if (\is_numeric($param)) {
|
||||
$param = \ucfirst($type);
|
||||
continue 2;
|
||||
}
|
||||
if (\is_string($param)) {
|
||||
$param = sprintf('String(%d)', \strlen($param));
|
||||
continue 2;
|
||||
}
|
||||
} //end switch
|
||||
} //end foreach
|
||||
return $params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Anonymize at least Sql queries
|
||||
*
|
||||
* @param string $message
|
||||
* @return string
|
||||
*/
|
||||
public static function getAnonymizedMessage(string $message): string
|
||||
{
|
||||
$message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message;
|
||||
if ($sqlPos = \strpos($message, 'to use near')) {
|
||||
$message = \mb_strcut($message, 0, $sqlPos);
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize stack trace
|
||||
*
|
||||
* @param \Throwable $e
|
||||
* @return string
|
||||
*/
|
||||
public static function getAnonymizedStackTrace(\Throwable $e): string
|
||||
{
|
||||
$projectPath = \realpath(\sprintf('%s/../', \app_path()));
|
||||
$traceStack = $e->getTrace();
|
||||
$traceStr = '';
|
||||
$maxStackStage = 0;
|
||||
foreach ($traceStack as $stackStage => $stack) {
|
||||
$maxStackStage = $stackStage;
|
||||
$traceStr .= \sprintf(
|
||||
'#%s %s(%d): ',
|
||||
$stackStage,
|
||||
str_replace($projectPath, '', $stack['file'] ?? ''),
|
||||
$stack['line'] ?? ''
|
||||
);
|
||||
if (isset($stack['class'])) {
|
||||
$traceStr .= "{$stack['class']}->{$stack['function']}(";
|
||||
if (isset($stack['args'])) {
|
||||
$traceStr .= self::handleArgs($stack);
|
||||
}
|
||||
$traceStr .= ")\n";
|
||||
} elseif (isset($stack['function'])) {
|
||||
$traceStr .= "{$stack['function']}(";
|
||||
if (isset($stack['args'])) {
|
||||
$traceStr .= self::handleArgs($stack);
|
||||
}
|
||||
$traceStr .= ")\n";
|
||||
}
|
||||
} //end foreach
|
||||
$maxStackStage++;
|
||||
$traceStr .= "#$maxStackStage {main}";
|
||||
return $traceStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Args
|
||||
*
|
||||
* @param array $stack
|
||||
* @return string
|
||||
*/
|
||||
public static function handleArgs(array $stack): string
|
||||
{
|
||||
$traceArgs = '';
|
||||
$argsCount = count($stack['args']);
|
||||
for ($i = 0; $i < $argsCount; $i++) {
|
||||
$type = \gettype($stack['args'][$i]);
|
||||
switch ($type) {
|
||||
case 'object':
|
||||
$traceArgs .= sprintf('Object(%s)', \get_class($stack['args'][$i]));
|
||||
break;
|
||||
case 'array':
|
||||
$traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i]));
|
||||
break;
|
||||
case 'string':
|
||||
$traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i]));
|
||||
break;
|
||||
default:
|
||||
$traceArgs .= \gettype($stack['args'][$i]);
|
||||
}
|
||||
$traceArgs .= ($i !== ($argsCount - 1) ? ',' : '');
|
||||
}
|
||||
return $traceArgs;
|
||||
}
|
||||
}
|
||||
454
app/Lib/Helpers/FileStorageHelper.php
Normal file
454
app/Lib/Helpers/FileStorageHelper.php
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
<?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} === ToolboxHelper::getOriginal($model, $attribute)) {
|
||||
return;
|
||||
}
|
||||
$originalPath = \ltrim(\urldecode(ToolboxHelper::getOriginal($model, $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.
|
||||
* @param boolean $private To store the file in a private space.
|
||||
* @return string
|
||||
* @throws \RuntimeException If file copy fails.
|
||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
*/
|
||||
public static function storeFile(
|
||||
Model $model,
|
||||
$file,
|
||||
bool $slugify = false,
|
||||
string $filename = null,
|
||||
bool $private = false
|
||||
): string {
|
||||
// phpcs:enable
|
||||
$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, $private);
|
||||
$newPath = str_replace(storage_path('app'), '', $newPath);
|
||||
|
||||
if (!$private) {
|
||||
// * Store public file.
|
||||
$file->storePubliclyAs(
|
||||
pathinfo($newPath, \PATHINFO_DIRNAME),
|
||||
pathinfo($newPath, \PATHINFO_BASENAME)
|
||||
);
|
||||
return 'storage' . str_replace('/public', '', $newPath);
|
||||
}
|
||||
|
||||
$file->storeAs(
|
||||
pathinfo($newPath, \PATHINFO_DIRNAME),
|
||||
pathinfo($newPath, \PATHINFO_BASENAME)
|
||||
);
|
||||
|
||||
return str_replace('/private/', '', $newPath);
|
||||
}//end if
|
||||
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, $private);
|
||||
if (!File::copy($file->getRealPath(), $newPath)) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Failed to copy file %s to %s',
|
||||
$file->getRealPath(),
|
||||
$newPath
|
||||
));
|
||||
}
|
||||
return $private ?
|
||||
\ltrim(str_replace(\storage_path('app/private'), '/storage/app/private', $newPath), '/') :
|
||||
\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.
|
||||
* @param boolean $private May the file be stored in a private dir.
|
||||
* @return string
|
||||
*/
|
||||
private static function prepareMoveFile(string $tableName, string $filename, bool $private = false): string
|
||||
{
|
||||
// * Security filter
|
||||
$filename = \htmlspecialchars($filename);
|
||||
// * Security filter + beautifier
|
||||
$filename = self::sanitizeFileName($filename);
|
||||
// * Slugify filename
|
||||
$ext = \pathinfo($filename, \PATHINFO_EXTENSION);
|
||||
$filename = Str::slug(\pathinfo($filename, \PATHINFO_FILENAME)) .
|
||||
(\strlen($ext) ? ".{$ext}" : '');
|
||||
|
||||
$folderPath = self::getStoragePath(
|
||||
$private ? 'app/private/modelfiles' : 'app/public/modelfiles',
|
||||
$tableName,
|
||||
$filename,
|
||||
$private
|
||||
);
|
||||
$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 $storage_dir
|
||||
* @param string $table
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
private static function getStoragePath(string $storage_dir, string $table, string $filename): string
|
||||
{
|
||||
$filenameHash = \md5($filename);
|
||||
$pathFolder = \storage_path(sprintf(
|
||||
'%s/%s/%s/%s/%s/%s',
|
||||
$storage_dir,
|
||||
$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 have 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;
|
||||
}
|
||||
}
|
||||
324
app/Lib/Helpers/ToolboxHelper.php
Normal file
324
app/Lib/Helpers/ToolboxHelper.php
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Helpers;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class ToolboxHelper
|
||||
{
|
||||
/**
|
||||
* 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 => trans(
|
||||
'crud.libs.toolbox.assertNoInternalBoUrls',
|
||||
['attribute' => $field]
|
||||
)
|
||||
]);
|
||||
}
|
||||
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 => trans(
|
||||
'crud.libs.toolbox.assertNoInternalUrls',
|
||||
['attribute' => $field, 'appname' => config('app.name')]
|
||||
)
|
||||
]);
|
||||
}
|
||||
return $match;
|
||||
} catch (NotFoundHttpException $e) {
|
||||
return $match;
|
||||
}
|
||||
},
|
||||
$text
|
||||
);
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutltibyte string replace
|
||||
*
|
||||
* @param array|string $search
|
||||
* @param array|string $replace
|
||||
* @param array|string $subject
|
||||
* @param integer $count
|
||||
* @return array|string
|
||||
*/
|
||||
public static function mbReplace(
|
||||
array|string $search,
|
||||
array|string $replace,
|
||||
array|string $subject,
|
||||
int &$count = 0
|
||||
): array|string {
|
||||
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 string|integer|float|boolean|null|array $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,
|
||||
string|int|float|bool|null|array $value,
|
||||
?int $id = null,
|
||||
?callable $query = null
|
||||
) {
|
||||
if (!$query) {
|
||||
Validator::make([$field => $value], [
|
||||
self::mbReplace('.', '\.', $field) => Rule::unique($table, $field)->ignore($id),
|
||||
], [
|
||||
self::mbReplace('.', '\.', "{$field}.unique")
|
||||
=> trans('crud.libs.toolbox.assertFieldIsUnique', ['attribute' => $field, 'value' => $value])
|
||||
])->validate();
|
||||
return;
|
||||
}
|
||||
Validator::make([$field => $value], [
|
||||
$field => Rule::unique($table)->where($query)->ignore($id),
|
||||
], [
|
||||
$field . '.unique' => trans(
|
||||
'crud.libs.toolbox.assertFieldIsUnique',
|
||||
['attribute' => $field, 'value' => $value]
|
||||
)
|
||||
])->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get original polyfill with autotranslate behavior
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $attribute
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getOriginal(Model $model, string $attribute): mixed
|
||||
{
|
||||
if (\in_array('Spatie\Translatable\HasTranslations', \class_uses_recursive($model))) {
|
||||
return $model->getTranslation(
|
||||
$attribute,
|
||||
$model->getLocale(),
|
||||
$model->useFallbackLocale()
|
||||
);
|
||||
}
|
||||
return $model->getOriginal($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic model query
|
||||
*
|
||||
* @param string $defaultLocale
|
||||
* @param \Illuminate\Contracts\Database\Eloquent\Builder $q
|
||||
* @param string $column
|
||||
* @param string $value
|
||||
* @return \Illuminate\Contracts\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function queryColumnWithLocales(
|
||||
string $defaultLocale,
|
||||
Builder $q,
|
||||
string $column,
|
||||
string $value
|
||||
): Builder {
|
||||
$currentLocale = app()->currentLocale();
|
||||
$locales = collect(config('app.locales'))
|
||||
->mapWithKeys(fn (string $locale) => [$locale => $locale]);
|
||||
if (!$locales->has($defaultLocale)) {
|
||||
// * Remove default locale.
|
||||
$locales->pull($defaultLocale);
|
||||
}
|
||||
if (!$locales->has($currentLocale)) {
|
||||
// * Remove current locale.
|
||||
$locales->pull($currentLocale);
|
||||
}
|
||||
|
||||
return $q->where(function (Builder $q) use ($defaultLocale, $currentLocale, $locales, $column, $value) {
|
||||
// * Query default locale
|
||||
$q->whereRaw("JSON_EXTRACT({$column}, '$.{$defaultLocale}') = '{$value}'");
|
||||
if ($defaultLocale !== $currentLocale) {
|
||||
// * Query current locale
|
||||
$q->whereRaw("JSON_EXTRACT({$column}, '$.{$currentLocale}') = '{$value}'");
|
||||
}
|
||||
// * Query any other locale
|
||||
$locales->each(fn ($locale) => $q->orWhereRaw(
|
||||
"JSON_EXTRACT({$column}, '$.{$locale}') = '{$value}'"
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an array from a dot separated string
|
||||
*
|
||||
* @param string $path
|
||||
* @param mixed $value
|
||||
* @param string $separator
|
||||
* @return array
|
||||
*/
|
||||
public static function dotStringToNestedArray(string $path, mixed $value, string $separator = '.'): array
|
||||
{
|
||||
$arr = $value;
|
||||
$keys = array_reverse(explode($separator, $path));
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$arr = [$key => $arr];
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert deeply an object to array
|
||||
*
|
||||
* @param array|object $input
|
||||
* @return array
|
||||
* @throws \RuntimeException If $input var is a scalar value.
|
||||
*/
|
||||
public static function objectToArray($input): array
|
||||
{
|
||||
// Only process if it's an object or array being passed to the function.
|
||||
if (is_object($input) or is_array($input)) {
|
||||
$ret = (array)$input;
|
||||
foreach ($ret as &$item) {
|
||||
// Recursively process EACH element only if not scalar.
|
||||
$item = (is_object($item) or is_array($item)) ?
|
||||
self::objectToArray($item) : $item;
|
||||
}
|
||||
return $ret;
|
||||
} else {
|
||||
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert deeply an array to object
|
||||
*
|
||||
* @param array|object $input
|
||||
* @return object
|
||||
* @throws \RuntimeException If $input var is a scalar value.
|
||||
*/
|
||||
public static function arrayToObject($input): object
|
||||
{
|
||||
// Only process if it's an object or array being passed to the function.
|
||||
if (is_object($input) or is_array($input)) {
|
||||
$ret = (object)$input;
|
||||
foreach ($ret as &$item) {
|
||||
// Recursively process EACH element only if not scalar.
|
||||
$item = (is_object($item) or is_array($item)) ?
|
||||
self::arrayToObject($item) : $item;
|
||||
}
|
||||
return $ret;
|
||||
} else {
|
||||
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
|
||||
}
|
||||
}
|
||||
}
|
||||
83
app/Mail/ContactMessageReceived.php
Normal file
83
app/Mail/ContactMessageReceived.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ContactMessageReceived extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param string $first_name
|
||||
* @param string $last_name
|
||||
* @param string $email
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
private string $first_name,
|
||||
private string $last_name,
|
||||
private string $email,
|
||||
private string $message,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return \Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: \trans('Kontaktformular :appname', [
|
||||
'appname' => \config('app.name')
|
||||
]),
|
||||
from: new Address(
|
||||
'info@wenndannmitrespekt.de',
|
||||
'Kontaktformular wenndannmitrespekt.de'
|
||||
),
|
||||
to: new Address(
|
||||
'kontakt@wenndannmitrespekt.de',
|
||||
'kontakt@wenndannmitrespekt.de'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return \Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
markdown: 'emails.contact-message-received',
|
||||
with: [
|
||||
'first_name' => $this->first_name,
|
||||
'last_name' => $this->last_name,
|
||||
'email' => $this->email,
|
||||
'message' => $this->message,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
313
app/Models/Concept.php
Normal file
313
app/Models/Concept.php
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\Concepts\ColorsEnum;
|
||||
use App\Enums\InputType;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\HasTranslations;
|
||||
use App\Traits\Models\IsCachedAsCollection;
|
||||
use App\Traits\Models\MiniCrudModel;
|
||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* @property string $seo_title
|
||||
* @property string $seo_description
|
||||
* @property string $name
|
||||
* @property string $slug
|
||||
* @property string $title
|
||||
* @property string $subtitle
|
||||
* @property string $description
|
||||
* @property object $data
|
||||
* @property string $picture
|
||||
* @property string $picture_alt
|
||||
* @property string $picture_title
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Concept extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
use IsCachedAsCollection;
|
||||
use MiniCrudModel;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'name',
|
||||
'slug',
|
||||
'title',
|
||||
'subtitle',
|
||||
'description',
|
||||
'data',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'order',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'data' => 'object',
|
||||
];
|
||||
|
||||
/**
|
||||
* The translatable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatable = [
|
||||
'data',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'name',
|
||||
'slug',
|
||||
'title',
|
||||
'subtitle',
|
||||
'description',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::assertFieldIsUnique('name', $model->name);
|
||||
self::manageFields($model);
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::created(function () {
|
||||
self::removeCached();
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
self::removeCached();
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * - Cache
|
||||
/**
|
||||
* Change query for cached elements
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
protected static function queryCached(Builder $query): Builder
|
||||
{
|
||||
return $query->where('id', '<>', 1)->orderBy('order');
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Common methods function.
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
self::setSlug($model);
|
||||
ToolboxHelper::assertNoInternalBoUrls('description', $model->description);
|
||||
$model->description = clean($model->description);
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the slug.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function setSlug(Model $model)
|
||||
{
|
||||
$model->slug = Str::slug($model->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the structure necessary of data.
|
||||
*
|
||||
* @param string $title
|
||||
* @param integer $color
|
||||
* @param string $text
|
||||
* @param string $img
|
||||
* @param string $imgAlt
|
||||
* @param string $imgTitle
|
||||
* @return ((string|\App\Enums\InputType)[]|(string|int[]|\App\Enums\InputType)[]|(string|\App\Enums\InputType|int|(string|\Illuminate\Validation\Rules\Enum)[])[])[]
|
||||
*/
|
||||
public static function getEmptyData(
|
||||
string $title = '',
|
||||
int $color = 0,
|
||||
string $text = '',
|
||||
string $img = '',
|
||||
string $imgAlt = '',
|
||||
string $imgTitle = ''
|
||||
) {
|
||||
$color = $color ?: \collect(ColorsEnum::cases())->random()->value;
|
||||
return [
|
||||
// * BLOC 1
|
||||
"bloc_1_title" => [
|
||||
"label" => "Bloc 1 - Title",
|
||||
"inputType" => InputType::string->value,
|
||||
"value" => $title,
|
||||
"validate" => "required|min:4|max:100"
|
||||
],
|
||||
"bloc_1_color" => [
|
||||
"label" => "Bloc 1 - Color",
|
||||
"inputType" => InputType::selectEnum->value,
|
||||
"value" => $color,
|
||||
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
|
||||
],
|
||||
"bloc_1_text" => [
|
||||
"label" => "Bloc 1 - Text",
|
||||
"inputType" => InputType::text->value,
|
||||
"value" => $text,
|
||||
"validate" => "string|min:10"
|
||||
],
|
||||
"bloc_1_image" => [
|
||||
"label" => "Bloc 1 - Image",
|
||||
"dimensions" => ["width" => 1140, "height" => 795],
|
||||
"inputType" => InputType::image->value,
|
||||
"alt" => $imgAlt,
|
||||
"title" => $imgTitle,
|
||||
"value" => $img,
|
||||
],
|
||||
// * BLOC 2
|
||||
"bloc_2_title" => [
|
||||
"label" => "Bloc 2 - Title",
|
||||
"inputType" => InputType::string->value,
|
||||
"value" => $title,
|
||||
"validate" => "required|min:4|max:100"
|
||||
],
|
||||
"bloc_2_color" => [
|
||||
"label" => "Bloc 2 - Color",
|
||||
"inputType" => InputType::selectEnum->value,
|
||||
"value" => $color,
|
||||
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
|
||||
],
|
||||
"bloc_2_text" => [
|
||||
"label" => "Bloc 2 - Text",
|
||||
"inputType" => InputType::text->value,
|
||||
"value" => $text,
|
||||
"validate" => "string|min:10"
|
||||
],
|
||||
"bloc_2_image" => [
|
||||
"label" => "Bloc 2 - Image",
|
||||
"dimensions" => ["width" => 1140, "height" => 795],
|
||||
"inputType" => InputType::image->value,
|
||||
"alt" => $imgAlt,
|
||||
"title" => $imgTitle,
|
||||
"value" => $img,
|
||||
],
|
||||
// * BLOC 3
|
||||
"bloc_3_title" => [
|
||||
"label" => "Bloc 3 - Title",
|
||||
"inputType" => InputType::string->value,
|
||||
"value" => $title,
|
||||
"validate" => "required|min:4|max:100"
|
||||
],
|
||||
"bloc_3_color" => [
|
||||
"label" => "Bloc 3 - Color",
|
||||
"inputType" => InputType::selectEnum->value,
|
||||
"value" => $color,
|
||||
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
|
||||
],
|
||||
"bloc_3_text" => [
|
||||
"label" => "Bloc 3 - Text",
|
||||
"inputType" => InputType::text->value,
|
||||
"value" => $text,
|
||||
"validate" => "string|min:10"
|
||||
],
|
||||
"bloc_3_image" => [
|
||||
"label" => "Bloc 3 - Image",
|
||||
"dimensions" => ["width" => 1140, "height" => 795],
|
||||
"inputType" => InputType::image->value,
|
||||
"alt" => $imgAlt,
|
||||
"title" => $imgTitle,
|
||||
"value" => $img,
|
||||
],
|
||||
// * BLOC 4
|
||||
"bloc_4_title" => [
|
||||
"label" => "Bloc 4 - Title",
|
||||
"inputType" => InputType::string->value,
|
||||
"value" => $title,
|
||||
"validate" => "required|min:4|max:100"
|
||||
],
|
||||
"bloc_4_color" => [
|
||||
"label" => "Bloc 4 - Color",
|
||||
"inputType" => InputType::selectEnum->value,
|
||||
"value" => $color,
|
||||
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
|
||||
],
|
||||
"bloc_4_text" => [
|
||||
"label" => "Bloc 4 - Text",
|
||||
"inputType" => InputType::text->value,
|
||||
"value" => $text,
|
||||
"validate" => "string|min:10"
|
||||
],
|
||||
"bloc_4_image" => [
|
||||
"label" => "Bloc 4 - Image",
|
||||
"dimensions" => ["width" => 1140, "height" => 795],
|
||||
"inputType" => InputType::image->value,
|
||||
"alt" => $imgAlt,
|
||||
"title" => $imgTitle,
|
||||
"value" => $img,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
155
app/Models/Home.php
Normal file
155
app/Models/Home.php
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\HasTranslations;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property integer $part2_product1_id
|
||||
* @property integer $part2_product2_id
|
||||
* @property string $seo_title
|
||||
* @property string $seo_description
|
||||
* @property string $part1_title
|
||||
* @property string $part1_subtitle
|
||||
* @property string $part1_text_1
|
||||
* @property string $part1_text_2
|
||||
* @property string $part1_text_3
|
||||
* @property string $part2_title
|
||||
* @property string $part2_subtitle
|
||||
* @property string $part2_text
|
||||
* @property array $part2_list
|
||||
* @property string $part3_picture
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Home extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'part2_product1_id',
|
||||
'part2_product2_id',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'part1_title',
|
||||
'part1_subtitle',
|
||||
'part1_text_1',
|
||||
'part1_text_2',
|
||||
'part1_text_3',
|
||||
'part2_title',
|
||||
'part2_subtitle',
|
||||
'part2_text',
|
||||
'part2_list',
|
||||
'part3_picture',
|
||||
'part3_picture_alt',
|
||||
'part3_picture_title',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'part2_list' => 'array',
|
||||
];
|
||||
|
||||
/**
|
||||
* The translatable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'part1_title',
|
||||
'part1_subtitle',
|
||||
'part1_text_1',
|
||||
'part1_text_2',
|
||||
'part1_text_3',
|
||||
'part2_title',
|
||||
'part2_subtitle',
|
||||
'part2_text',
|
||||
'part2_list',
|
||||
'part3_picture',
|
||||
'part3_picture_alt',
|
||||
'part3_picture_title',
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'part3_picture');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'part3_picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
ToolboxHelper::assertNoInternalBoUrls('part1_text_1', $model->part1_text_1);
|
||||
ToolboxHelper::assertNoInternalBoUrls('part1_text_2', $model->part1_text_2);
|
||||
ToolboxHelper::assertNoInternalBoUrls('part1_text_3', $model->part1_text_3);
|
||||
ToolboxHelper::assertNoInternalBoUrls('part2_text', $model->part2_text);
|
||||
if (is_array($model->part2_list)) {
|
||||
foreach ($model->part2_list as $item) {
|
||||
ToolboxHelper::assertNoInternalBoUrls('part2_list', $item['value']);
|
||||
}
|
||||
}
|
||||
$model->part1_text_1 = clean($model->part1_text_1);
|
||||
$model->part1_text_2 = clean($model->part1_text_2);
|
||||
$model->part1_text_3 = clean($model->part1_text_3);
|
||||
$model->part2_text = clean($model->part2_text);
|
||||
$model->part2_list = clean($model->part2_list);
|
||||
$model->part3_picture = FileStorageHelper::storeFile($model, $model->part3_picture, true);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function product1()
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'part2_product1_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function product2()
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'part2_product2_id');
|
||||
}
|
||||
}
|
||||
227
app/Models/Product.php
Normal file
227
app/Models/Product.php
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\HasTranslations;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property integer $range_id
|
||||
* @property string $seo_title
|
||||
* @property string $seo_description
|
||||
* @property string $label
|
||||
* @property string $slug
|
||||
* @property string $description
|
||||
* @property string $picture
|
||||
* @property array $certifications
|
||||
* @property array $nutritionnal_values
|
||||
* @property array $list
|
||||
* @property boolean $status
|
||||
* @property integer $order
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Product extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'range_id',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'label',
|
||||
'slug',
|
||||
'description',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'certifications',
|
||||
'nutritionnal_values',
|
||||
'list',
|
||||
'status',
|
||||
'order',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'certifications' => 'array',
|
||||
'nutritionnal_values' => 'array',
|
||||
'list' => 'array',
|
||||
];
|
||||
|
||||
/**
|
||||
* The translatable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'label',
|
||||
'slug',
|
||||
'description',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'nutritionnal_values',
|
||||
'list',
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::assertFieldIsUnique('label', $model->label);
|
||||
self::manageFields($model);
|
||||
self::cleanTranslationJsonFields($model, 'nutritionnal_values', 'list');
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
self::cleanTranslationJsonFields($model, 'nutritionnal_values', 'list');
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
self::setSlug($model);
|
||||
if (is_array($model->list)) {
|
||||
foreach ($model->list as $itemList) {
|
||||
ToolboxHelper::assertNoInternalBoUrls('list', $itemList['value'] ?? '');
|
||||
}
|
||||
}
|
||||
if (is_array($model->nutritionnal_values)) {
|
||||
foreach ($model->nutritionnal_values as $itemNutritionnalValues) {
|
||||
ToolboxHelper::assertNoInternalBoUrls('nutritionnal_values', $itemNutritionnalValues['label'] ?? '');
|
||||
ToolboxHelper::assertNoInternalBoUrls('nutritionnal_values', $itemNutritionnalValues['value'] ?? '');
|
||||
}
|
||||
}
|
||||
$model->nutritionnal_values = clean($model->nutritionnal_values);
|
||||
$model->list = clean($model->list);
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the original array from json field
|
||||
*
|
||||
* @param Model $model
|
||||
* @param string ...$fields The names of the json fields.
|
||||
* @return void
|
||||
*/
|
||||
private static function cleanTranslationJsonFields(Model $model, string ...$fields): void
|
||||
{
|
||||
foreach ($fields as $field) {
|
||||
$translations = $model->getTranslations($field);
|
||||
foreach ($translations as $key => $trans) {
|
||||
if (!in_array($key, config('app.locales'))) {
|
||||
$model->forgetTranslation($field, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the slug.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function setSlug(Model $model)
|
||||
{
|
||||
$model->slug = Str::slug($model->label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function recipes()
|
||||
{
|
||||
return $this->belongsToMany('App\Models\Recipe', 'recipes_products');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function range()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Range');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function homes1()
|
||||
{
|
||||
return $this->hasMany('App\Models\Home', 'part2_product1_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function homes2()
|
||||
{
|
||||
return $this->hasMany('App\Models\Home', 'part2_product2_id');
|
||||
}
|
||||
}
|
||||
150
app/Models/Range.php
Normal file
150
app/Models/Range.php
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\Ranges\PictoEnum;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\HasTranslations;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property string $seo_title
|
||||
* @property string $seo_description
|
||||
* @property string $label
|
||||
* @property string $slug
|
||||
* @property string $picto
|
||||
* @property integer $order
|
||||
* @property boolean $status
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Range extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'label',
|
||||
'slug',
|
||||
'picto',
|
||||
'order',
|
||||
'status',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'picto' => PictoEnum::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The translatable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'label',
|
||||
'slug',
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
self::assertFieldIsUnique('label', $model->label);
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Set the slug.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function setSlug(Model $model)
|
||||
{
|
||||
$model->slug = Str::slug($model->label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Common methods function
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
self::setSlug($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function recipes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Recipe');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany('App\Models\Product');
|
||||
}
|
||||
}
|
||||
227
app/Models/Recipe.php
Normal file
227
app/Models/Recipe.php
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\Recipes\DifficultyEnum;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\HasTranslations;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property integer $range_id
|
||||
* @property string $seo_title
|
||||
* @property string $seo_description
|
||||
* @property string $name
|
||||
* @property string $slug
|
||||
* @property string $picture
|
||||
* @property string $picture_thumbnail
|
||||
* @property string $ingredients
|
||||
* @property string $teaser
|
||||
* @property string $steps
|
||||
* @property \App\Enums\Recipes\DifficultyEnum $difficulty
|
||||
* @property string $duration
|
||||
* @property string $tips
|
||||
* @property boolean $status
|
||||
* @property integer $order
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Recipe extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'range_id',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'name',
|
||||
'slug',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'picture_thumbnail',
|
||||
'picture_thumbnail_alt',
|
||||
'picture_thumbnail_title',
|
||||
'ingredients',
|
||||
'teaser',
|
||||
'steps',
|
||||
'difficulty',
|
||||
'duration',
|
||||
'tips',
|
||||
'status',
|
||||
'order',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'ingredients' => 'json',
|
||||
'difficulty' => DifficultyEnum::class
|
||||
];
|
||||
|
||||
/**
|
||||
* The translatable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'name',
|
||||
'slug',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'picture_thumbnail',
|
||||
'picture_thumbnail_alt',
|
||||
'picture_thumbnail_title',
|
||||
'ingredients',
|
||||
'duration',
|
||||
'teaser',
|
||||
'steps',
|
||||
'tips',
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::assertFieldIsUnique('name', $model->name);
|
||||
self::setSlug($model);
|
||||
self::manageFields($model);
|
||||
self::cleanTranslationJsonFields($model, 'ingredients');
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
self::cleanTranslationJsonFields($model, 'ingredients');
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
FileStorageHelper::removeOldFile($model, 'picture_thumbnail');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
FileStorageHelper::removeFile($model, 'picture_thumbnail');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Common methods function.
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
if (is_array($model->ingredients)) {
|
||||
foreach ($model->ingredients as $itemIngredients) {
|
||||
if (isset($itemIngredients['header'])) {
|
||||
ToolboxHelper::assertNoInternalBoUrls('ingredients', $itemIngredients['header']);
|
||||
}
|
||||
ToolboxHelper::assertNoInternalBoUrls('ingredients', \strval($itemIngredients['value']));
|
||||
}
|
||||
}
|
||||
ToolboxHelper::assertNoInternalBoUrls('steps', $model->steps);
|
||||
ToolboxHelper::assertNoInternalBoUrls('tips', $model->tips);
|
||||
$model->ingredients = clean($model->ingredients);
|
||||
$model->steps = clean($model->steps);
|
||||
$model->tips = clean($model->tips);
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
$model->picture_thumbnail = FileStorageHelper::storeFile($model, $model->picture_thumbnail, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the original array from json field
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string ...$fields The names of the json fields.
|
||||
* @return void
|
||||
*/
|
||||
private static function cleanTranslationJsonFields(Model $model, string ...$fields): void
|
||||
{
|
||||
foreach ($fields as $field) {
|
||||
$translations = $model->getTranslations($field);
|
||||
foreach ($translations as $key => $trans) {
|
||||
if (!in_array($key, config('app.locales'))) {
|
||||
$model->forgetTranslation($field, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the slug.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function setSlug(Model $model)
|
||||
{
|
||||
$model->slug = Str::slug($model->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
return $this->belongsToMany(Product::class, 'recipes_products');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function range()
|
||||
{
|
||||
return $this->belongsTo(Range::class);
|
||||
}
|
||||
}
|
||||
154
app/Models/Slider.php
Normal file
154
app/Models/Slider.php
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\Sliders\TypeEnum;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\HasTranslations;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property boolean $type
|
||||
* @property string $title
|
||||
* @property string $subtitle
|
||||
* @property string $description
|
||||
* @property string $link
|
||||
* @property string $link_title
|
||||
* @property boolean $link_new_tab
|
||||
* @property string $picture
|
||||
* @property boolean $status
|
||||
* @property integer $order
|
||||
* @property string $unpublish_at
|
||||
* @property string $publish_at
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Slider extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'type',
|
||||
'title',
|
||||
'subtitle',
|
||||
'description',
|
||||
'link',
|
||||
'link_title',
|
||||
'link_new_tab',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'status',
|
||||
'order',
|
||||
'unpublish_at',
|
||||
'publish_at',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The translatable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatable = [
|
||||
'title',
|
||||
'subtitle',
|
||||
'description',
|
||||
'link',
|
||||
'link_title',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'type' => TypeEnum::class,
|
||||
'status' => 'bool',
|
||||
'publish_at' => 'datetime',
|
||||
'unpublish_at' => 'datetime'
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::assertFieldIsUnique('title', $model->title);
|
||||
self::manageFields($model);
|
||||
self::setOrder($model);
|
||||
if (!$model->status) {
|
||||
$model->publish_at = null;
|
||||
} else {
|
||||
$model->unpublish_at = null;
|
||||
}
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Common methods function.
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
if ($model->link) {
|
||||
ToolboxHelper::assertNoInternalBoUrls('link', $model->link);
|
||||
}
|
||||
ToolboxHelper::assertNoInternalBoUrls('description', $model->description);
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
}
|
||||
86
app/Models/Store.php
Normal file
86
app/Models/Store.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property integer $type_id
|
||||
* @property integer $region_id
|
||||
* @property string $state
|
||||
* @property string $street
|
||||
* @property string $zipcode
|
||||
* @property string $city
|
||||
* @property float $latitude
|
||||
* @property float $longitude
|
||||
* @property integer $order
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Store extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'type_id',
|
||||
'region_id',
|
||||
'state',
|
||||
'street',
|
||||
'zipcode',
|
||||
'city',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'order',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::setOrder($model);
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function storeType()
|
||||
{
|
||||
return $this->belongsTo(StoreType::class, 'type_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function storeRegion()
|
||||
{
|
||||
return $this->belongsTo(StoreRegion::class, 'region_id');
|
||||
}
|
||||
}
|
||||
104
app/Models/StoreGroup.php
Normal file
104
app/Models/StoreGroup.php
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property string $picture
|
||||
* @property integer $order
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class StoreGroup extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'picture',
|
||||
'order',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::assertFieldIsUnique('name', $model->name);
|
||||
self::manageFields($model);
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function storeRegions()
|
||||
{
|
||||
return $this->hasMany(StoreRegion::class, 'group_id');
|
||||
}
|
||||
}
|
||||
113
app/Models/StoreRegion.php
Normal file
113
app/Models/StoreRegion.php
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property integer $group_id
|
||||
* @property string $name
|
||||
* @property string $picture
|
||||
* @property integer $order
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class StoreRegion extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'group_id',
|
||||
'name',
|
||||
'picture',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
self::assertFieldIsUnique('name', $model->name);
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(Model $model)
|
||||
{
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function stores()
|
||||
{
|
||||
return $this->hasMany(Store::class, 'region_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function storeGroup()
|
||||
{
|
||||
return $this->belongsTo(StoreGroup::class, 'group_id');
|
||||
}
|
||||
}
|
||||
78
app/Models/StoreType.php
Normal file
78
app/Models/StoreType.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class StoreType extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::assertFieldIsUnique('name', $model->name);
|
||||
self::setOrder($model);
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function stores()
|
||||
{
|
||||
return $this->hasMany(Store::class, 'type_id');
|
||||
}
|
||||
}
|
||||
65
app/Models/User.php
Normal file
65
app/Models/User.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'firstname',
|
||||
'lastname',
|
||||
'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',
|
||||
];
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
// * EVENT CLOSURES.
|
||||
static::creating(function (self $model) {
|
||||
if (Hash::needsRehash($model->password)) {
|
||||
$model->password = Hash::make($model->password);
|
||||
}
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
if (Hash::needsRehash($model->password)) {
|
||||
$model->password = Hash::make($model->password);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
106
app/Providers/AppServiceProvider.php
Normal file
106
app/Providers/AppServiceProvider.php
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Concept;
|
||||
use App\Models\Home;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Spatie\Translatable\Facades\Translatable;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
// * 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'));
|
||||
|
||||
Translatable::fallback(
|
||||
fallbackAny: true,
|
||||
);
|
||||
|
||||
$this->sharetoView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Share Vars to view
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function sharetoView()
|
||||
{
|
||||
if (app()->runningInConsole()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// * FORCE BOOTSTRAP PAGINATOR (or custom if in front)
|
||||
// Early boot, request wont be filled as expected.
|
||||
if (collect(explode('/', \request()->getPathInfo()))->get(1) === 'bo') {
|
||||
Paginator::useBootstrap();
|
||||
} else {
|
||||
Paginator::useBootstrap();
|
||||
}
|
||||
|
||||
// * FORCE BOOTSTRAP PAGINATOR (or custom if in front)
|
||||
// Early boot, request wont be filled as expected.
|
||||
if (collect(explode('/', \request()->getPathInfo()))->get(1) === 'bo') {
|
||||
Paginator::defaultview('bo.modules.pagination');
|
||||
} else {
|
||||
Paginator::defaultview('fo.modules.pagination');
|
||||
}
|
||||
|
||||
$appInfos = Cache::remember('composer', 360, function () {
|
||||
return json_decode(File::get(\app_path('../composer.json')));
|
||||
});
|
||||
// Share composer.json infos.
|
||||
if (
|
||||
isset($appInfos->name) and isset($appInfos->version) and
|
||||
isset($appInfos->license) and isset($appInfos->time)
|
||||
) {
|
||||
View::share('cpsr_name', $appInfos->name);
|
||||
View::share('cpsr_version', $appInfos->version);
|
||||
View::share('cpsr_license', $appInfos->license);
|
||||
View::share('cpsr_time', now()->parse($appInfos->time)->isoFormat('Y'));
|
||||
}
|
||||
View::share('globalHome', Home::query()->first());
|
||||
View::share('conceptListGlobal', Concept::getCached());
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue