Compare commits

..

395 commits

Author SHA1 Message Date
Vincent BRIDIER
ad4218da01 Merge branch 'trunk' 2026-10-23 15:51:35 +02:00
Vincent BRIDIER
376c5d3ab1 Merge branch 'develop' into trunk 2026-10-23 15:51:10 +02:00
Vincent BRIDIER
2e07125c62 Merge branch 'fix-user-group' into 'develop'
fix: 🐛 update alpine www-data

See merge request ldc-web/projets/volena!79
2026-10-23 15:50:06 +02:00
Corentin Huet
ef17ae64e3 fix: 🐛 update alpine www-data 2026-10-23 14:33:18 +02:00
K Muller
ea4848ede8 Merge branch 'develop' into trunk 2026-08-13 13:12:23 +02:00
Karl M'muller
d5edac7cba Merge branch 'update' into 'develop'
fix: 🚸 check if nav links is empty, then display or not the...

See merge request ldc-web/projets/volena!78
2026-08-13 11:11:41 +00:00
Alexis Gousseau
74015163b7
chore: ⬆️ bump husky-config to v1.1.1 2026-08-06 10:00:03 +02:00
Alexis Gousseau
c3e34984d6
fix: 🚸 check if nav links is empty, then display or not the button navigation in front 2026-08-06 09:58:18 +02:00
K Muller
10eede1282 Merge branch 'trunk' 2026-07-29 09:01:55 +02:00
K Muller
d695c04d81 Merge branch 'develop' into trunk 2026-07-29 09:01:23 +02:00
Karl M'muller
d7a81c939d Merge branch 'activity-logs-clean' into 'develop'
fix: 🐛 add the queue + env variable

See merge request ldc-web/projets/volena!77
2026-07-29 07:00:44 +00:00
K Muller
f5b0f9fd66 fix: 🐛 add the queue + env variable 2026-07-23 11:09:05 +02:00
K Muller
9007631dc9 fix: 🐛 revolve conflict 2026-07-23 09:08:03 +02:00
karl.muller
a646ecd84b Merge branch 'hotfix' into 'main'
fix: 🐛 testimonials routes missing

See merge request ldc-web/projets/volena!76
2026-06-03 07:59:44 +00:00
K Muller
455277669a fix: 🐛 testimonials routes missing 2026-06-03 09:59:00 +02:00
Noah Lancien
3d86d1fa5f Merge branch 'develop' into trunk 2026-06-02 09:09:38 +02:00
Noah Lancien
5f4a4b4ecb fix: 🐛 broken overflow on hire carousels 2026-06-02 09:09:17 +02:00
karl.muller
d38010dbdc Merge branch 'hotfix' into 'main'
fix: 🐛 update target fields to sanitize #101 - 898ce4d962

See merge request ldc-web/projets/volena!75
2026-06-01 10:57:19 +00:00
K Muller
10e8655192 fix: 🐛 update target fields to sanitize #101 - 898ce4d962 2026-06-01 12:55:50 +02:00
K Muller
2d20d563fe Merge branch 'develop' into trunk 2026-06-01 12:51:22 +02:00
karl.muller
f42a2d7deb Merge branch 'issue-101' into 'develop'
fix: 🐛 update target fields to sanitize #101

See merge request ldc-web/projets/volena!74
2026-06-01 10:50:46 +00:00
K Muller
3948787e3d Merge branch 'develop' into trunk 2026-06-01 11:19:59 +02:00
karl.muller
737d17652a Merge branch '97-stickies' into 'develop'
feat: ✨ Added color column to sticky model + keep sticky displayed on mobile

See merge request ldc-web/projets/volena!73
2026-06-01 09:13:51 +00:00
Alexis Gousseau
898ce4d962
fix: 🐛 update target fields to sanitize #101 2026-06-01 10:51:22 +02:00
Noah Lancien
9f564c61ed feat: ✨ Added color column to sticky model + keep sticky displayed on mobile 2026-05-28 11:54:19 +02:00
Noah Lancien
31b7df079b Merge branch 'develop' into trunk 2026-05-12 15:52:25 +02:00
Noix
d926451557 Merge branch '98-fix-sticky' into 'develop'
fix: 🐛 fix z-index on stickies

See merge request ldc-web/projets/volena!71
2026-05-12 13:51:58 +00:00
Corentin Huet
0f7da74206 fix: 🐛 fix z-index on stickies 2026-05-11 11:54:45 +02:00
Noah Lancien
ecc0a42044 Merge branch 'trunk' 2026-04-29 09:12:16 +02:00
Noah Lancien
88c38f7a6c Merge branch 'develop' into trunk 2026-04-29 09:11:39 +02:00
Noah Lancien
25c7a9bef3 fix: 🐛 require saml package in normal part, not require-dev 2026-04-29 09:10:57 +02:00
Noah Lancien
b62e258070 Merge branch 'trunk' 2026-04-28 09:18:45 +02:00
Noah Lancien
f415475878 Merge branch 'develop' into trunk 2026-04-28 09:18:33 +02:00
Noah Lancien
02c4f35683 ci: 👷 Added @uwil npm config in Dockerfile + ci multi-stage 2026-04-28 09:18:20 +02:00
Noah Lancien
79a709e3f4 Merge branch 'trunk' 2026-04-28 09:06:18 +02:00
Noah Lancien
8b582376b0 Merge branch 'develop' into trunk 2026-04-28 09:05:37 +02:00
Noix
3f1e5c765c Merge branch 'issue-96' into 'develop'
Issue 96

See merge request ldc-web/projets/volena!69
2026-04-28 07:03:41 +00:00
Noix
11e82b9a1c Merge branch 'issue-90' into 'develop'
fix: 🔥 remove double click on leaflet markers #90

See merge request ldc-web/projets/volena!70
2026-04-28 07:01:37 +00:00
Alexis Gousseau
d3af7c03be
feat: 🔧 add assets cache in .htaccess 2026-04-27 10:10:01 +02:00
Alexis Gousseau
5fe32c9f73
fix: 🔥 remove double click on leaflet markers #90 2026-04-24 15:25:52 +02:00
Alexis Gousseau
6add647e12
feat: ✨ add commit lint from husky configuration 2026-04-24 15:14:21 +02:00
Alexis Gousseau
e7330d27f8
chore: 👷 use variable to define version of docker image 2026-04-24 15:14:21 +02:00
Alexis Gousseau
70d9f09a0e
feat: 🔧 add redirection to omit index.php in .htaccess 2026-04-24 15:14:16 +02:00
Alexis Gousseau
0c9d7da807
fix: 🚨 resolve phpstan errors with strict level 7 2026-04-24 15:06:55 +02:00
Alexis Gousseau
93e4ed4cae
fix: 🐛 replace old 24slides/laravel-saml2 dependency from scaler-tech/laravel-saml2 2026-04-24 15:03:52 +02:00
Alexis Gousseau
e6c0fe65e2
fix: 🐛 save only updated models in planificated status job 2026-04-24 11:08:16 +02:00
Alexis Gousseau
a50ca7f133
feat: ✨ add job to clean activity logs older than one year #96 2026-04-24 11:07:58 +02:00
Noah Lancien
249172d18e Merge branch 'trunk' 2026-04-22 12:08:18 +02:00
Noah Lancien
dd50c67623 Merge branch 'develop' into trunk 2026-04-10 10:31:18 +02:00
Noah Lancien
9e7cfc2a76 ci: 👷 Updated docker image 2026-04-10 10:31:10 +02:00
Noah Lancien
6a5a679b62 Merge branch 'develop' into trunk 2026-04-10 10:20:19 +02:00
Noah Lancien
7dbd427cb6 chore: ⬆️ Updated to php8.5 + phpcs/phpstan 2026-04-10 10:19:45 +02:00
Noah Lancien
2f6948bf5e Merge branch 'develop' into trunk 2026-04-09 10:24:36 +02:00
Noix
f1cd325a4d Merge branch '93-fix-carousel' into 'develop'
fix: 🐛 add missing arrows to the slider, add component for ordering carousels

See merge request ldc-web/projets/volena!68
2026-04-09 08:23:48 +00:00
Noix
cc3a09f39e Merge branch '70-feedback' into 'develop'
fix: 🐛 correct publish validation, fix translation, and add slider indicators

See merge request ldc-web/projets/volena!67
2026-04-09 08:23:33 +00:00
Noix
fde2cc3e02 Merge branch '85-fix-slider' into 'develop'
feat: ✨ add navigation arrows on mobile

See merge request ldc-web/projets/volena!66
2026-04-09 08:22:56 +00:00
Corentin Huet
3a4ec13798 fix: 🐛 add missing arrows to the slider, add component for ordering carousels 2026-03-30 09:49:40 +02:00
Corentin Huet
ef44546aea fix: 🐛 correct publish validation, fix translation, and add slider indicators 2026-03-27 14:22:54 +01:00
Corentin Huet
82abf4518e feat: ✨ add navigation arrows on mobile 2026-03-27 10:15:35 +01:00
Noah Lancien
77be8ce26d Merge branch 'develop' into trunk 2026-03-25 15:41:36 +01:00
noah.lancien
cfffe97e06 Merge branch '86-strips-img' into 'develop'
feat: ✨ allow choosing between picto or image and slow down strip animation by 30%

See merge request ldc-web/projets/volena!60
2026-03-25 14:41:04 +00:00
Corentin Huet
9358cf32b9 fix: 🐛 remove list-item class causing conflict with vue component 2026-03-25 15:26:07 +01:00
Corentin Huet
75dd8de967 fix: 🚨 resolve phpcs and phpstan errors 2026-03-25 15:25:30 +01:00
Corentin Huet
5b74ca5e78 feat: ✨ allow choosing between picto or image and slow down strip animation by 30% 2026-03-25 15:25:27 +01:00
noah.lancien
4b281f8abf Merge branch '88-stickies' into 'develop'
Resolve "TS-3147 : PAGE "ON SE DÉVOILE" AJOUT DE STICKY"

See merge request ldc-web/projets/volena!58
2026-03-25 14:23:53 +00:00
Corentin Huet
906e81cda7 feat: ✨ add migration to seed sticky elements 2026-03-25 15:13:06 +01:00
Corentin Huet
5e9e542d87 fix: 🐛 resolve various bugs 2026-03-25 15:00:51 +01:00
Corentin Huet
a3a01e5296 feat: ✨ add stickies on unveil page 2026-03-25 11:58:36 +01:00
Corentin Huet
edd9028336 feat: ✨ implement CRUD stickies 2026-03-25 11:58:30 +01:00
noah.lancien
f52db3b50b Merge branch '93-images-wehire' into 'develop'
feat: ✨ implement carousel CRUD + add fields to parity section + set...

See merge request ldc-web/projets/volena!64
2026-03-25 10:42:47 +00:00
Corentin Huet
5d77c5d158 feat: ✨ implement carousel CRUD + add fields to parity section + set fields as nullable on parity and formation sections 2026-03-25 11:38:28 +01:00
noah.lancien
17b35bb20c Merge branch '82-homepage' into 'develop'
feat: ✨ update logo and increase slider transition speed

See merge request ldc-web/projets/volena!56
2026-03-25 10:36:57 +00:00
Corentin Huet
45b5fb538f fix: 🐛 remove default search on slides page 2026-03-25 11:23:42 +01:00
Corentin Huet
ae7dd18bda feat: ✨ update logo and increase slider transition speed 2026-03-25 11:20:48 +01:00
noah.lancien
20a6ed4ac0 Merge branch '90-map' into 'develop'
feat: ✨ show pin markers on zoom out and enable site navigation on marker double-click

See merge request ldc-web/projets/volena!63
2026-03-24 16:34:20 +00:00
noah.lancien
45f0ac7434 Merge branch '70-bugs' into 'develop'
fix: 🐛 resolve various bugs following re7 feedback

See merge request ldc-web/projets/volena!62
2026-03-24 16:31:48 +00:00
noah.lancien
139b61290c Merge branch '89-re7-feedback' into 'develop'
fix: 🐛 anchor title and link were not being saved

See merge request ldc-web/projets/volena!65
2026-03-24 16:30:52 +00:00
noah.lancien
3990442d39 Merge branch '84-crud-stickys' into 'develop'
feat: ✨ implement CRUD stickies

See merge request ldc-web/projets/volena!57
2026-03-24 16:29:20 +00:00
Corentin Huet
ed5807645d fix: 🐛 anchor title and link were not being saved 2026-03-23 12:24:03 +01:00
Corentin Huet
860cbe272b fix: 🚨 resolve phpcs and phpstan errors 2026-03-13 15:46:34 +01:00
Corentin Huet
0a07237aa7 refactor: ♻️ make changeCustomOrder generic 2026-03-13 14:28:53 +01:00
Corentin Huet
9bb18429bb fix: 🚨 resolve phpcs errors 2026-03-13 11:55:17 +01:00
Corentin Huet
a9201415c9 feat: ✨ implement CRUD stickies 2026-03-12 16:43:44 +01:00
K Muller
c8ac89ca3a Merge branch 'develop' into trunk 2026-03-12 10:09:23 +01:00
karl.muller
f3a4e2fc80 Merge branch '91-site' into 'develop'
feat: ✨ make site manager  editable and allow inversion of  blocks

See merge request ldc-web/projets/volena!55
2026-03-12 09:09:05 +00:00
Corentin Huet
67e4885fd5 feat: ✨ make site manager editable and allow inversion of blocks 2026-03-12 09:56:19 +01:00
K Muller
7b45466952 Merge branch 'develop' into trunk 2026-03-12 09:34:19 +01:00
karl.muller
27d5d7b2b9 Merge branch '81-logo-baseline' into 'develop'
feat: ✨ update logo and baseline

See merge request ldc-web/projets/volena!51
2026-03-12 08:33:40 +00:00
karl.muller
e8820543b8 Merge branch '87-brands' into 'develop'
feat: ✨ remove brand logo block

See merge request ldc-web/projets/volena!52
2026-03-12 08:33:24 +00:00
karl.muller
34ddb7f4fa Merge branch '83-menu' into 'develop'
feat: ✨ move on embauche page after on produit

See merge request ldc-web/projets/volena!53
2026-03-12 08:32:44 +00:00
karl.muller
4035ce0002 Merge branch '92-actu' into 'develop'
feat: ✨ hide linkedin logo when news is not published on linkedin

See merge request ldc-web/projets/volena!54
2026-03-12 08:32:14 +00:00
karl.muller
a6863b507d Merge branch '89-sticky-site' into 'develop'
feat: ✨ add sticky on site page

See merge request ldc-web/projets/volena!59
2026-03-12 08:31:13 +00:00
karl.muller
749628540b Merge branch '85-slider-btn' into 'develop'
feat: ✨ add left and right arrows to navigate between years

See merge request ldc-web/projets/volena!61
2026-03-12 08:30:52 +00:00
Corentin Huet
074320d79c fix: 🐛 resolve various bugs following re7 feedback 2026-03-10 15:05:00 +01:00
Corentin Huet
91dd2c81e3 feat: ✨ show pin markers on zoom out and enable site navigation on marker double-click 2026-03-10 12:06:49 +01:00
Corentin Huet
93a5181b4d feat: ✨ add sticky on site page 2026-03-06 10:56:58 +01:00
Corentin Huet
8e1ca12c9f feat: ✨ add left and right arrows to navigate between years 2026-03-06 09:44:24 +01:00
Noah Lancien
bbbd9ce526 ci: added UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST variable 2026-03-05 10:03:34 +01:00
Corentin Huet
fbd5829aef feat: ✨ update logo and baseline 2026-03-04 14:59:10 +01:00
Corentin Huet
2f3310220c feat: ✨ hide linkedin logo when news is not published on linkedin 2026-03-04 11:27:04 +01:00
Corentin Huet
a169b2c2e1 feat: ✨ move on embauche page after on produit 2026-03-04 11:15:07 +01:00
Corentin Huet
5f9a4496eb feat: ✨ remove brand logo block 2026-03-04 11:07:51 +01:00
Noah Lancien
33810d36fc Merge branch 'develop' into trunk 2026-03-03 10:16:35 +01:00
Noah Lancien
6e6757cd77 ci: added project related ips variable 2026-03-03 10:16:19 +01:00
Noah Lancien
0fabceb1f3 Merge branch 'develop' into trunk 2026-01-22 11:49:51 +01:00
Noah Lancien
af3d961dea fix: added missing bootstrap style 2026-01-22 11:49:39 +01:00
Noah Lancien
03fdf04437 Merge branch 'develop' into trunk 2026-01-22 11:15:57 +01:00
noah.lancien
2e23543a0d Merge branch '70-network-pages' into 'develop'
feat: Added network part in 'produce' page + networks, aisles and brands models

See merge request ldc-web/projets/volena!50
2026-01-22 10:11:52 +00:00
Noah Lancien
6f3e459a65 ci: limit jobs history to 1 + migrate to mysql 2026-01-22 11:10:19 +01:00
Noah Lancien
c00caa1dc3 feat: Added network part in 'produce' page + networks, aisles and brands models 2026-01-21 14:51:03 +01:00
Noah Lancien
7f5e6173c9 Merge branch 'trunk' 2026-01-12 16:06:14 +01:00
Noah Lancien
7ff95fdb5f Merge branch 'develop' into trunk 2026-01-12 16:05:22 +01:00
Noah Lancien
3a3415c61e feat: added admin-secure 2026-01-12 16:05:00 +01:00
Noah Lancien
3a064fd47f Merge branch 'develop' into trunk 2026-01-08 14:46:01 +01:00
Noah Lancien
a344a89466 ci: added ci variables to define pod resources 2026-01-08 14:29:36 +01:00
Noah Lancien
a0d3c95305 Merge branch 'trunk' 2025-10-16 14:54:10 +02:00
Vincent BRIDIER
4d5bf6a135 fix: Fix redirects domaines ssl challenge 2025-10-16 12:03:26 +02:00
Vincent BRIDIER
ddf876ea0b Merge branch 'develop' into trunk 2025-10-16 11:55:24 +02:00
Vincent BRIDIER
fad0d13c8f fix: Fix redirects domaines ssl challenge 2025-10-16 11:55:15 +02:00
Noah Lancien
aceee89f39 feat: added volailles ramon redirections to volena.fr 2025-10-16 09:16:36 +02:00
Noah Lancien
abb326134f Merge branch 'develop' into trunk 2025-10-16 09:07:15 +02:00
noah.lancien
7ca3e0333b Merge branch '80-redirection' into 'develop'
feat: added volailles ramon redirections to volena.fr

See merge request ldc-web/projets/volena!49
2025-10-16 07:04:58 +00:00
Corentin Huet
b834747955 feat: added volailles ramon redirections to volena.fr 2025-10-15 10:50:24 +02:00
Noah Lancien
7da3f98667 Merge branch 'develop' into trunk 2025-10-08 10:43:16 +02:00
Noah Lancien
cacee5c21d ci: added staging-resources.yaml 2025-10-08 10:43:01 +02:00
Noah Lancien
773c59aafc Merge branch 'develop' into trunk 2025-10-08 10:35:03 +02:00
noah.lancien
efc250ba16 Merge branch '79-bug-banner' into 'develop'
fix: images from static pages are now saved in the storage folder

See merge request ldc-web/projets/volena!48
2025-10-08 08:33:00 +00:00
Corentin Huet
ee912e4163 fix: images from static pages are now saved in the storage folder 2025-10-06 12:42:48 +02:00
K Muller
9da5674696 Merge branch 'trunk' 2025-09-04 15:56:13 +02:00
K Muller
cab82c9ecd Merge branch 'develop' into trunk 2025-09-04 15:55:49 +02:00
karl.muller
4f02895ac8 Merge branch 'contact-validation' into 'develop'
fix: 🐛 add array merge in listenFormRequest to have correct validation

See merge request ldc-web/projets/volena!47
2025-09-04 13:54:08 +00:00
Nicolas Demangeat
8cfc757995 fix: 🐛 add array merge in listenFormRequest to have correct validation 2025-08-21 08:44:04 +02:00
Karl
bd6f7e5358 Merge branch 'trunk' 2025-07-24 10:24:23 +02:00
Karl
6f0348a6ff Merge branch 'develop' into trunk 2025-07-24 10:24:01 +02:00
karl.muller
a424fc724d Merge branch 'issue-78' into 'develop'
Issue 78

See merge request ldc-web/projets/volena!45
2025-07-24 08:23:31 +00:00
karl.muller
1bedaaee6e Merge branch 'issue-77' into 'develop'
fix: 🐛 display the correct date for the news in news card.blade and show.blade

See merge request ldc-web/projets/volena!46
2025-07-24 08:23:20 +00:00
Nicolas Demangeat
f5ca726c66 fix: 🐛 display the correct date for the news in news card.blade and show.blade 2025-07-22 09:53:58 +02:00
Nicolas Demangeat
19e2fc4f6a fix: 🩹 add numeric validation for phone and postal_code in ListenFormRequest 2025-07-22 09:06:26 +02:00
Nicolas Demangeat
d70dbce0f6 fix: 🐛 remove number in ListenFormRequest 2025-07-21 15:27:39 +02:00
Nicolas Demangeat
08bb5c9180 chore: 🎨 improve some code 2025-07-21 15:27:01 +02:00
Noah Lancien
63208d568a Merge branch 'trunk' 2025-07-10 14:39:48 +02:00
Noah Lancien
754ed2c734 Merge branch 'develop' into trunk 2025-07-08 16:41:30 +02:00
noah.lancien
ad0e6802d3 Merge branch 'issue-74' into 'develop'
fix: 🐛 add section query in StaticPageController in listen method to have...

See merge request ldc-web/projets/volena!44
2025-07-08 14:39:56 +00:00
Nicolas Demangeat
e025969e93 fix: 🐛 add section query in StaticPageController in listen method to have the section h2 and text 2025-07-08 15:52:31 +02:00
Noah Lancien
f09df54d90 Merge branch 'develop' into trunk 2025-07-04 15:24:28 +02:00
Noah Lancien
33a0206ade fix: display picture for obiles in the hire page (company life section) 2025-07-04 15:24:09 +02:00
Noah Lancien
d59d7a9781 Merge branch 'develop' into trunk 2025-07-03 16:31:58 +02:00
Noah Lancien
53a285ec9f ci: update image version + replace 443 port by 80 in manifest 2025-07-03 16:31:47 +02:00
Noah Lancien
2ec44a2584 Merge branch 'develop' into trunk 2025-07-03 16:19:14 +02:00
noah.lancien
43d6b4d652 Merge branch 'issue-73' into 'develop'
fix: 🐛 update strip news list by taking into account dates in home page #73

See merge request ldc-web/projets/volena!42
2025-07-03 14:17:40 +00:00
noah.lancien
58ca2372aa Merge branch 'issue-72' into 'develop'
fix: 💄 delete class to display image on mobile #72

See merge request ldc-web/projets/volena!43
2025-07-03 14:16:25 +00:00
Alexis Gousseau
0929272440
fix: 🐛 update strip news list by taking into account dates in home page #73 2025-07-03 15:49:57 +02:00
Alexis Gousseau
3904db884a
fix: 💄 delete class to display image on mobile #72 2025-07-03 13:22:00 +02:00
Karl
abd47e2aed Merge branch 'trunk' 2025-05-15 16:52:59 +02:00
Karl
33f0594bc6 Merge branch 'develop' into trunk 2025-05-15 16:52:28 +02:00
Vincent BRIDIER
d4ef6e4b44 Merge branch 'issue-71' into 'develop'
fix: 🐛 🚑 add clean method to the slider in homepage

See merge request ldc-web/projets/volena!41
2025-05-09 07:29:54 +00:00
Nicolas Demangeat
156a9b8fa7 fix: 🚨 phpcs and phpstan 2025-05-07 14:57:11 +02:00
Nicolas Demangeat
7cb3c668d9 fix: 🐛🚑 add clean method to the slider in homepage 2025-05-07 09:38:30 +02:00
Noah Lancien
dd80e4c8d5 Merge branch 'trunk' 2025-03-14 11:19:38 +01:00
Noah Lancien
24cbab746b Merge branch 'develop' into trunk 2025-03-14 10:54:02 +01:00
noah.lancien
ad0e0fc436 Merge branch 'fix-ckeditor-file-upload' into 'develop'
fix: file upload was broken on ckeditor fields

See merge request ldc-web/projets/volena!39
2025-03-14 09:53:43 +00:00
Noah Lancien
0843331f01 fix: file upload was broken on ckeditor fields 2025-03-14 10:50:26 +01:00
Karl Muller
c05d1c3e0a Merge branch 'trunk' 2025-03-06 16:42:48 +00:00
Karl Muller
9959bb4a24 Merge branch 'develop' into trunk 2025-03-06 16:42:34 +00:00
Karl Muller
993dc6ed88 fix: 🐛 add manifest variable 2025-03-06 16:42:22 +00:00
Karl Muller
92800c4282 Merge branch 'trunk' 2025-03-06 15:51:00 +00:00
Karl Muller
fcc49f0189 Merge branch 'develop' into trunk 2025-03-06 15:50:41 +00:00
Karl Muller
ac98b01925 fix: 🐛 change php version on Dockerfile 2025-03-06 15:50:16 +00:00
Karl Muller
cadc478ea9 Merge branch 'trunk' 2025-03-06 15:06:23 +00:00
Karl Muller
6a5fdba063 Merge branch 'develop' into trunk 2025-03-06 15:05:52 +00:00
karl.muller
57c22e5ea5 Merge branch 'bump/laravel11' into 'develop'
bump: 📦 laravel 11 + sitemap + saml + robots.txt

See merge request ldc-web/projets/volena!38
2025-03-06 15:04:56 +00:00
Karl Muller
bdf748c1b7 fix: resolve conflicts 2025-03-06 14:56:45 +00:00
Karl Muller
36c877d6be bump: 📦 laravel 11 + sitemap + saml + robots.txt 2025-03-06 14:51:21 +00:00
Noah Lancien
b13b34e860 Merge branch 'develop' into trunk 2025-03-05 11:51:36 +01:00
noah.lancien
16d3c0e552 Merge branch 'issue-29-organization' into 'develop'
reorganize navbar bo #29

See merge request ldc-web/projets/volena!37
2025-03-05 10:50:35 +00:00
Corentin Huet
4ec3428928 refactor: ♻️ aremoved unused imports 2025-03-05 11:48:05 +01:00
Corentin Huet
f0e3f5df91 refactor: ♻️ add better solution for set nav item as active when a sectioon is editing 2025-03-05 11:28:46 +01:00
Corentin Huet
6466cb7f5f refactor: move methods from controllers to models 2025-03-04 15:55:50 +01:00
root
fccfc1734e feat: ✨ organize navbar bo 2025-02-27 16:43:22 +01:00
Noah Lancien
b85ac4fe9d Merge branch 'develop' into trunk 2025-02-27 09:37:40 +01:00
noah.lancien
242ca9bc35 Merge branch 'issue-57-fix' into 'develop'
fix: revert enum deletion

See merge request ldc-web/projets/volena!36
2025-02-27 08:37:17 +00:00
Noah Lancien
da66e2322c fix: revert enum deletion 2025-02-26 18:05:27 +01:00
Noah Lancien
cda965c645 Merge branch 'develop' into trunk 2025-02-20 17:40:39 +01:00
noah.lancien
65d170cd90 Merge branch 'issue-41' into 'develop'
feat: Make static pages banner manageable

See merge request ldc-web/projets/volena!35
2025-02-20 16:33:11 +00:00
noah.lancien
6e7203306d Merge branch 'issue-33' into 'develop'
fix: remove unused content field for contact page

See merge request ldc-web/projets/volena!34
2025-02-20 16:32:08 +00:00
Noah Lancien
8d4b48c03e feat: Make static pages banner manageable 2025-02-20 17:28:04 +01:00
Noah Lancien
1e6cc6166c fix: remove unused content field for contact page 2025-02-20 15:19:30 +01:00
Noah Lancien
60607f8931 Merge branch 'develop' into trunk 2025-02-20 14:24:50 +01:00
noah.lancien
546f955171 Merge branch 'issue-33' into 'develop'
feat: add team slide in BO

See merge request ldc-web/projets/volena!30
2025-02-20 13:23:46 +00:00
Noah Lancien
0a05fe76b5 fix: don't re-instantiate Slide Model to get min and max 2025-02-20 12:51:25 +01:00
Noah Lancien
241b8d6a42 feat: limit team slides between 1 and 3, added ckeditor for content field and fix error messages 2025-02-20 11:44:16 +01:00
Vincent BRIDIER
b2f2dc77d5
Merge branch 'trunk' 2025-02-18 12:57:36 +01:00
Vincent BRIDIER
f090b12405
Merge branch 'develop' into trunk 2025-02-18 12:55:10 +01:00
Vincent BRIDIER
e0a9133f96 Merge branch 'issue-69' into 'develop'
fix: 🐛 change custom binding conditions

See merge request ldc-web/projets/volena!33
2025-02-18 11:54:31 +00:00
Sebastien Hattry
852861b838 fix: 🐛 change custom binding conditions 2025-01-28 09:10:41 +01:00
Karl Muller
cdf0a866dc Merge branch 'trunk' 2025-01-13 12:05:12 +00:00
Karl Muller
4491ddaff5 Merge branch 'develop' into trunk 2025-01-13 12:00:59 +00:00
Karl Muller
21ef4b1e1f fix: composer update to fix CVE 2025-01-13 12:00:12 +00:00
Karl Muller
a525a36c4b Merge branch 'trunk' 2024-11-28 09:17:15 +00:00
Karl Muller
1c3aecf556 Merge branch 'develop' into trunk 2024-11-28 09:10:29 +00:00
karl.muller
2229e96a57 Merge branch 'hot-fix-slide' into 'develop'
fix: ♻️ add "latest" to the slideLifeModels and slideEarthModels query...

See merge request ldc-web/projets/volena!32
2024-11-28 09:09:44 +00:00
Noah Lancien
45277f1c0b Merge branch 'trunk' 2024-11-27 15:06:28 +01:00
Noah Lancien
33773f90cc Merge branch 'develop' into trunk 2024-11-27 15:04:44 +01:00
Noah Lancien
a90393391f chore: composer update to fix CVE 2024-11-27 15:04:27 +01:00
Nicolas Demangeat
08f99d0fa5 fix: ♻️ add "latest" to the slideLifeModels and slideEarthModels query in Fo StaticPageController 2024-11-27 15:01:23 +01:00
Noah Lancien
6b089ce172 Merge branch 'develop' into trunk 2024-11-27 14:43:35 +01:00
noah.lancien
b203269c5e Merge branch 'issue-66' into 'develop'
fix: 🐛 improve contact form to display input file when added

See merge request ldc-web/projets/volena!31
2024-11-27 13:42:03 +00:00
Nicolas Demangeat
7111f9adee fix: phpcs 2024-11-27 14:20:28 +01:00
Nicolas Demangeat
f5b8deee6a fix: reformating the comment in listen blade 2024-11-27 14:13:03 +01:00
Nicolas Demangeat
e89c6224ff fix: 🐛 ternaire in listenFormRequest 2024-11-27 14:04:12 +01:00
Nicolas Demangeat
51051adc56 fix: phpStan and phpCs 2024-11-27 12:02:33 +01:00
Nicolas Demangeat
a43edd883d fix: remove unuse code 2024-11-27 11:59:28 +01:00
Nicolas Demangeat
546e2d102e fix: 🐛 improve contact form to display input file when added 2024-11-27 11:52:18 +01:00
Sebastien Hattry
5defc78270 feat: add team slide in BO 2024-08-02 16:17:59 +02:00
Noah Lancien
68193ec8c8 Merge branch 'trunk' 2024-08-02 14:21:51 +02:00
Noah Lancien
2d9fd8eb06 Merge branch 'develop' into trunk 2024-08-02 14:21:21 +02:00
noah.lancien
3352142d54 Merge branch 'sitemap' into 'develop'
Added sitemap

See merge request ldc-web/projets/volena!29
2024-08-02 12:20:32 +00:00
Noah Lancien
bffbfdabc6 Added sitemap 2024-08-02 12:48:06 +02:00
Noah Lancien
fc797ccc4f Merge branch 'develop' into trunk 2024-07-31 11:20:38 +02:00
Noah Lancien
551253516d Updated production-resources.yaml 2024-07-31 11:18:16 +02:00
Noah Lancien
0c99ea0af0 Merge branch 'trunk' 2024-07-30 18:57:18 +02:00
Noah Lancien
09914575e7 Merge branch 'develop' into trunk 2024-07-30 09:05:06 +02:00
Noah Lancien
6615233ac7 fix: in news.index, an id was missing 2024-07-30 09:04:54 +02:00
Noah Lancien
758648fcc8 Merge branch 'develop' into trunk 2024-07-29 16:59:21 +02:00
Noah Lancien
57cc782078 fix: added missing padding to header anchors 2024-07-29 16:59:13 +02:00
Noah Lancien
cdc915c9f9 Merge branch 'develop' into trunk 2024-07-29 16:35:58 +02:00
Noah Lancien
6904bf16a6 fix: replaced fancybox with fslightbox 2024-07-29 16:35:46 +02:00
Noah Lancien
4e285d85e3 Merge branch 'develop' into trunk 2024-07-29 15:31:43 +02:00
Noah Lancien
348cb1638d fix: fancybox youtube video link was wrong 2024-07-29 15:31:31 +02:00
Noah Lancien
8ddf9c66a3 Merge branch 'develop' into trunk 2024-07-29 15:09:37 +02:00
noah.lancien
2f498b01b4 Merge branch 'review-jm' into 'develop'
fix: max-height for carousel indicators

See merge request ldc-web/projets/volena!28
2024-07-29 13:09:05 +00:00
Noah Lancien
e03737544a phpcs 2024-07-29 15:03:03 +02:00
Noah Lancien
8750cc935b fix: #61 - limit carousel height in unveil page 2024-07-29 14:57:51 +02:00
Noah Lancien
a7d9d2d63a Merge branch 're7-fixes-again' into review-jm 2024-07-29 14:44:45 +02:00
Noah Lancien
64e481b63b feat: #60 - Added fancybox for the homepage video 2024-07-29 12:21:22 +02:00
Nicolas Demangeat
e064d2436f fix: issue-63 news index blade pagination 2024-07-29 11:30:56 +02:00
Noah Lancien
d992ac4484 fix: #64 Displayed quality section text in 'we produce' page 2024-07-29 11:09:57 +02:00
Nicolas Demangeat
fcae5436fa fix: issue-61 for unveil blade 2024-07-29 11:08:15 +02:00
Noah Lancien
477de0bc1d fix: #62 - commitments page - the slides title was not shown 2024-07-29 11:02:42 +02:00
Noah Lancien
d1855d8771 fix: #58 - pivot table logo_site was broken, foreign keys were inverted 2024-07-29 10:59:03 +02:00
Nicolas Demangeat
15c973798f fix: max-height for carousel indicators 2024-07-29 09:18:20 +02:00
Noah Lancien
1be7e6df68 Merge branch 'develop' into trunk 2024-07-26 12:34:51 +02:00
Noah Lancien
9065e3295a fix: disabled video autoplay 2024-07-26 12:34:25 +02:00
Noah Lancien
d2a61fb619 Merge branch 'develop' into trunk 2024-07-26 11:18:43 +02:00
Noah Lancien
6358ddd78d fix: updated pictures size in testimonial cards 2024-07-26 11:18:04 +02:00
Noah Lancien
e242ab8ac4 Merge branch 'develop' into trunk 2024-07-26 10:59:12 +02:00
noah.lancien
237c48f91e Merge branch 'feedback-jm' into 'develop'
Feedback jm

See merge request ldc-web/projets/volena!27
2024-07-26 08:55:41 +00:00
Noah Lancien
2f1ba3617f fix: Updated cn behaviour + video size 2024-07-26 10:45:32 +02:00
Noah Lancien
374f84c0d3 fix: Updated anchor links in banners 2024-07-26 10:41:29 +02:00
Nicolas Demangeat
5ddbae8889 fix: increasing image resolution in testimonial card 2024-07-26 10:31:20 +02:00
Noah Lancien
8fad33010d Merge branch 'feedback-jm' into feedback-jm-nl 2024-07-25 17:58:05 +02:00
Nicolas Demangeat
ef0501ba6e fix: wip video homepage and hirepage todo 2024-07-25 17:28:03 +02:00
Noah Lancien
aa8aa882a7 fix: 'next site' button on sites.show now loops on all the sites 2024-07-25 17:17:11 +02:00
Noah Lancien
c4abbf28e6 fix: added the target blank attribute to the report in commitments page when needed 2024-07-25 17:15:18 +02:00
Noah Lancien
ddea9f65c2 fix: updated historical milestones slider style 2024-07-25 17:12:00 +02:00
Nicolas Demangeat
e7035b8b40 fix: home blade and video-frame 2024-07-25 17:09:41 +02:00
Nicolas Demangeat
57378b1a17 fix: modul video-frame with cooki notice 2024-07-25 16:32:33 +02:00
Nicolas Demangeat
6b6f5f40fc fix: somes fix 2024-07-25 16:22:17 +02:00
Nicolas Demangeat
f48e658f6b fix: popup recaptcha button size 2024-07-25 16:14:51 +02:00
Nicolas Demangeat
ff27b87203 fix: Uppercase for button listen page 2024-07-25 16:12:52 +02:00
Noah Lancien
b2204f5d13 fix: pictos display in sites slider was broken in mobile 2024-07-25 15:59:14 +02:00
Nicolas Demangeat
c1c355e80c fix: video display in home and hire for mobile 2024-07-25 15:55:00 +02:00
Noah Lancien
df3a175de2 Merge branch 'develop' into trunk 2024-07-25 12:00:51 +02:00
Vincent BRIDIER
43ab9b75e9 Merge branch 're7-fixes' into 'develop'
Re7 fixes

See merge request ldc-web/projets/volena!26
2024-07-25 09:59:30 +00:00
Noah Lancien
d890f92741 Merge branch 'develop' into trunk 2024-07-25 11:47:30 +02:00
Noah Lancien
dfbd8d86ee Merge branch 're7-fixes' into develop 2024-07-25 11:46:49 +02:00
Noah Lancien
7c0a2fca0c fix: sites.show unveil link had incorrect title 2024-07-25 11:45:13 +02:00
Noah Lancien
355733d5b8 Merge remote-tracking branch 'origin/RGPD-conformite' into re7-fixes 2024-07-25 10:41:48 +02:00
Noah Lancien
a072b82904 Merge remote-tracking branch 'origin/issue-55' into re7-fixes 2024-07-25 10:40:41 +02:00
Noah Lancien
88e62ddc17 Merge remote-tracking branch 'origin/issue-57' into re7-fixes 2024-07-25 10:40:26 +02:00
Noah Lancien
5b7c943e6c fix: #53 - some style fixes in the commitments page + display or hide a pic in the hire page 2024-07-25 10:39:10 +02:00
Nicolas Demangeat
25f4e0a344 fix: add matomo in .env.example 2024-07-25 09:25:58 +02:00
Noah Lancien
3e3161cfa6 fix: #41 - Added pictures in pages banners 2024-07-24 18:08:51 +02:00
Nicolas Demangeat
c1d04e49e8 fix: comment produce show.blade 2024-07-24 17:49:30 +02:00
Noah Lancien
158f933fae fix: #32 - some fixes in hire page 2024-07-24 16:28:50 +02:00
Nicolas Demangeat
a2c6fc9771 fix: contact form 2024-07-24 16:24:05 +02:00
Nicolas Demangeat
83062ecec1 feat: add cookie-notice 6.0.4 + popup contact-form 2024-07-24 15:10:17 +02:00
Noah Lancien
17690e0bf8 fix: #31 - many style fixes on unveil page 2024-07-24 14:35:31 +02:00
Noah Lancien
7e76ad9b02 fix: #51 - display news strip in mobile 2024-07-24 12:19:47 +02:00
Nicolas Demangeat
30aad4c124 feat: can edit the content for legals in bo 2024-07-24 09:54:47 +02:00
Nicolas Demangeat
918d5a3dc8 fix: wip for produce page 2024-07-24 09:35:27 +02:00
Noah Lancien
f46da1e93f Merge branch 'hotfix' 2024-07-24 08:59:44 +02:00
Noah Lancien
a4166969e0 fix: images weren't loaded in errors pages 2024-07-24 08:58:44 +02:00
Noah Lancien
2348aa5af7 fix: #22 - Increased news thumbnails dimensions 2024-07-23 13:44:51 +02:00
Noah Lancien
114b98526f fix: #51 - some style fixes + YT and linkedin links 2024-07-23 12:15:23 +02:00
Noah Lancien
1952056b6d fix: #56 - reduced text width in headers 2024-07-23 11:25:52 +02:00
Vincent BRIDIER
3e4ea23684
Merge branch 'develop' into trunk 2024-07-11 15:40:35 +02:00
Vincent BRIDIER
c53a940dc0 Merge branch '49-picto-img' into 'develop'
fix: #49 - Replaced pictos imgs in home strip

See merge request ldc-web/projets/volena!22
2024-07-11 13:39:00 +00:00
Noah Lancien
a1ef12c19f fix: resized pictos imgs 2024-07-11 15:29:07 +02:00
Noah Lancien
48c0ddb3f0 fix: #49 - Replaced pictos imgs in home strip 2024-07-11 14:25:05 +02:00
Thibault Raquet
2cde39df0c Merge branch 'develop' into 'trunk'
Update manifest.yaml

See merge request ldc-web/projets/volena!21
2024-07-09 13:02:26 +00:00
Thibault Raquet
a8e5ffe776 Update manifest.yaml 2024-07-09 13:01:51 +00:00
Thibault Raquet
1a3315361c Merge branch 'develop' into 'trunk'
Update manifest.yaml

See merge request ldc-web/projets/volena!20
2024-07-09 12:48:54 +00:00
Thibault Raquet
5da558a90e Update manifest.yaml 2024-07-09 12:48:26 +00:00
Thibault Raquet
2e54c8a721 Merge branch 'develop' into 'trunk'
Update manifest.yaml

See merge request ldc-web/projets/volena!19
2024-07-09 12:18:55 +00:00
Thibault Raquet
31ae3ff676 Update manifest.yaml 2024-07-09 12:18:20 +00:00
Thibault Raquet
b00c974413 Merge branch 'develop' into 'trunk'
Develop

See merge request ldc-web/projets/volena!18
2024-07-09 08:30:58 +00:00
Thibault Raquet
a41a2bd141 Add new file 2024-07-09 08:30:21 +00:00
Thibault Raquet
c6a85ba9ca Update manifest.yaml 2024-07-09 08:29:42 +00:00
Thibault Raquet
8948aa796e Merge branch 'fix-ingressroute' into 'main'
Update manifest.yaml

See merge request ldc-web/projets/volena!17
2024-06-27 14:35:34 +00:00
Vincent BRIDIER
02b7ea8f2e Fix Errors imgs 2024-06-27 14:34:54 +00:00
Thibault Raquet
09ee2a5b91 Update manifest.yaml 2024-06-27 14:16:43 +00:00
Thibault Raquet
4201168131 Merge branch 'prod-migration' into 'main'
Prod migration

See merge request ldc-web/projets/volena!16
2024-06-27 13:52:18 +00:00
Thibault Raquet
9299b53b1b Prod migration 2024-06-27 13:52:18 +00:00
Vincent BRIDIER
1b3b07f4ef
Merge branch 'develop' into trunk 2024-06-27 12:47:53 +02:00
Vincent BRIDIER
d611575adb Merge branch 'swiper-teams' into 'develop'
feat: add   to have a correct display for the swiper-teams in the homepage

See merge request ldc-web/projets/volena!14
2024-06-27 10:47:34 +00:00
Vincent BRIDIER
7cfcbc200a
Merge branch 'develop' into trunk 2024-06-27 12:46:58 +02:00
Vincent BRIDIER
5465854892 Merge branch 'issue-48' into 'develop'
fix: somes fix related to issue 48, news bo + fo

See merge request ldc-web/projets/volena!15
2024-06-27 10:46:35 +00:00
nicolas.demangeat
07f8af2e90 fix: somes fix related to issue 48, news bo + fo 2024-06-27 10:46:35 +00:00
Vincent BRIDIER
aa44664e37
Merge branch 'develop' into trunk 2024-06-26 12:42:17 +02:00
Vincent BRIDIER
e04c789a80 Merge branch 'issue-35' into 'develop'
Issue 35

See merge request ldc-web/projets/volena!12
2024-06-26 10:39:52 +00:00
Nicolas Demangeat
7c33190d62 Merge branch 'develop' into issue-35 2024-06-26 12:36:31 +02:00
Nicolas Demangeat
c1472394bb fix: delete comment 2024-06-26 12:36:20 +02:00
Nicolas Demangeat
aee1df06b5 feat: add   to have a correct display for the swiper-teams in the homepage 2024-06-26 12:26:38 +02:00
Vincent BRIDIER
3a1a7e5fce Merge branch 'issues' into 'develop'
Issues

See merge request ldc-web/projets/volena!11
2024-06-26 10:22:23 +00:00
Vincent BRIDIER
5f83813f34 Merge branch 'issue-43' into 'develop'
fix: replace the lorem ipsum in the swiper-teams on homepage

See merge request ldc-web/projets/volena!13
2024-06-26 10:05:06 +00:00
Nicolas Demangeat
dd9330841e fix: replace the lorem ipsum in the swiper-teams on homepage 2024-06-26 12:03:44 +02:00
Sebastien Hattry
25e885ec08 Insert img in ck-editor block 2024-06-24 16:07:59 +02:00
Sebastien Hattry
a21a45d98f fix: del log + dev url 2024-06-21 16:13:53 +02:00
Sebastien Hattry
977260c240 feat: change front on sengage 2024-06-21 16:13:53 +02:00
Jérémy Munsch
61fc2b4c96
quality schema 2024-06-21 15:07:59 +02:00
Jérémy Munsch
173e2009c5
sections pieces 2024-06-21 14:58:09 +02:00
Jérémy Munsch
251d235930
fix 2024-06-21 10:01:15 +02:00
Jérémy Munsch
4fcb5e7f4d
link 2024-06-20 10:55:54 +02:00
Jérémy Munsch
324abfc92b
fix: Minicrud url could not be nullable 2024-06-20 09:57:54 +02:00
Jérémy Munsch
73a27598e1
no old value on input image 2024-06-20 09:26:35 +02:00
Jérémy Munsch
bc18f01f3e
bump ts code 2024-06-19 16:28:34 +02:00
Jérémy Munsch
1538e17a6b
Closes #45 2024-06-19 12:17:50 +02:00
Jérémy Munsch
77a1ba39e4
nav-menu html fix 2024-06-19 11:15:03 +02:00
Vincent BRIDIER
f8fe9c861c Merge branch 'bugfix-homepage' into 'develop'
change display and route

See merge request ldc-web/projets/volena!10
2024-06-18 14:45:48 +00:00
Vincent BRIDIER
40fb5e692d Merge branch 'fix-we-commit' into 'develop'
Fix we commit

See merge request ldc-web/projets/volena!9
2024-06-18 14:45:03 +00:00
Nicolas Demangeat
2a9996eb22 change display and route 2024-06-18 16:10:03 +02:00
Nicolas Demangeat
fdbba824b6 fix 🐛 alt image display 2024-06-18 15:58:07 +02:00
Vincent BRIDIER
1cf26fed67 Merge branch 'bugfix-we-move' into 'develop'
fix StoreNewsRequest pictureRules for picture

See merge request ldc-web/projets/volena!7
2024-06-18 12:44:01 +00:00
Nicolas Demangeat
66842b4220 fix helpers and request to match crea 2024-06-18 14:28:56 +02:00
Nicolas Demangeat
2fc3a7c432 add the active class when menu item selected 2024-06-18 14:07:33 +02:00
Vincent BRIDIER
5ca427c691 Merge branch 'issue-42' into 'develop'
Issue 42

See merge request ldc-web/projets/volena!8
2024-06-18 10:33:58 +00:00
Sebastien Hattry
ded761155c Change text positionning in responsive mode 2024-06-18 12:18:10 +02:00
Sebastien Hattry
ae2325a2b1 Change button positionning 2024-06-18 12:15:05 +02:00
Nicolas Demangeat
5e4b413067 fix StoreNewsRequest pictureRules for picture 2024-06-18 12:00:48 +02:00
Sebastien Hattry
a03d694071 npm audit fix 2024-06-18 11:44:00 +02:00
Jérémy Munsch
30ad03d92b
Merge branch 'develop' into trunk 2024-03-26 16:39:51 +01:00
Jérémy Munsch
e9618e79bb
add MAIL_CONTACT to manifest 2024-03-26 16:36:53 +01:00
Jérémy Munsch
e095b8f186
update CI file manifest and composer 2024-03-26 16:10:33 +01:00
Jérémy Munsch
6cbb4671dd
Merge branch 'develop' into trunk 2024-03-26 14:52:26 +01:00
Jérémy Munsch
d71d72af86 Merge branch '2.0.0' into 'develop'
2.0.0

See merge request ldc-web/projets/volena!3
2024-03-26 13:48:58 +00:00
Jérémy Munsch
fc3f0d1fae Merge branch 'issue-fo' into '2.0.0'
Volena FO Implementations

See merge request ldc-web/projets/volena!4
2024-03-26 13:48:35 +00:00
Jérémy Munsch
06c5b83b28
Setup site view pagge 2024-03-26 14:20:34 +01:00
Jérémy Munsch
afad70924b
Carto on Unveil ok 2024-03-26 12:23:04 +01:00
Jérémy Munsch
6cd2a87655
Working Map with overlaping spider and leaflet 2024-03-25 15:43:13 +01:00
Jérémy Munsch
f55b01b02c
npm audit fix 2024-03-22 16:34:21 +01:00
Jérémy Munsch
c9364bcd08
composer update and set php v to 8.3 2024-03-22 16:34:12 +01:00
Alexis Gousseau
1819fdb285 clean part 3 2024-03-22 12:48:19 +01:00
Alexis Gousseau
5f30d81ff2 clean part 2 2024-03-22 10:05:35 +01:00
Alexis Gousseau
8c664f426e WIP:clean de tout ce bordel 2024-03-22 09:23:24 +01:00
Alexis Gousseau
27e2336023 update site page 2024-03-21 10:07:02 +01:00
Alexis Gousseau
39612326fe update news.index & news.show pages 2024-03-20 16:44:57 +01:00
Noah Lancien
a7d3df2dde Updated anchor-padding class 2024-03-20 16:39:15 +01:00
Noah Lancien
0035e56ea0 Updated unveil page 2024-03-20 15:30:15 +01:00
Alexis Gousseau
d30cc71978 fix commitment page 2024-03-20 15:23:42 +01:00
Alexis Gousseau
54317c0e58 update home page 2024-03-20 12:57:46 +01:00
Alexis Gousseau
14097c0acf update we hire page 2024-03-20 12:55:20 +01:00
Noah Lancien
844e9d73e9 Fixed historical milestones slider 2024-03-20 12:54:38 +01:00
Nicolas Demangeat
b49654e567 rework homepage front and css, still 2 fixme 2024-03-19 11:42:36 +01:00
Alexis Gousseau
5b21cce220 clean section model 2024-03-19 10:37:33 +01:00
Alexis Gousseau
921d3e750e update layout + banner image 2024-03-19 10:37:14 +01:00
Nicolas Demangeat
0229a6dac5 add fixed position on strip in home page 2024-03-18 16:38:34 +01:00
Alexis Gousseau
8f46a19771 clean controllers 2024-03-18 16:10:01 +01:00
Alexis Gousseau
eae23a7a55 disallow bots to index /bo prefix 2024-03-18 15:49:57 +01:00
Alexis Gousseau
16f59a4a44 fix listen country field and recruitment button 2024-03-18 15:46:36 +01:00
Nicolas Demangeat
a511395990 update newspage css and news index blade 2024-03-18 14:04:44 +01:00
Nicolas Demangeat
1ec8692915 update hirepage css and blade 2024-03-18 14:03:55 +01:00
Nicolas Demangeat
ad399ba4fc add class for news.index and hire.show in footer 2024-03-18 14:02:22 +01:00
Nicolas Demangeat
5cb166e3bd improvement css for news show and news index, change paginate in newscontroller to have 4 items 2024-03-15 11:50:18 +01:00
Nicolas Demangeat
bdf0766d86 add linkedin button on news show, missing the href 2024-03-15 10:46:48 +01:00
Nicolas Demangeat
7805a088d4 Merge branch 'fix-news' into issue-fo 2024-03-15 10:00:47 +01:00
Nicolas Demangeat
04777c331e add next and prev button in show blade with and update show() method in newscontroller, some css 2024-03-15 09:59:40 +01:00
Noah Lancien
10d066ad91 Some accessibility/style fixes. Throttle midlleware fix on fo routes 2024-03-15 08:47:54 +01:00
Alexis Gousseau
8611f696d1 add 'we produce' page 2024-03-14 16:38:30 +01:00
Alexis Gousseau
4ab0de37b5 update routes name 2024-03-14 15:25:29 +01:00
Jérémy Munsch
7e5631fade
fix cookie link 2024-03-14 14:38:39 +01:00
Noah Lancien
1eaf6c1da7 Accessibility on commitments-page done with Tanaguru (except colors) 2024-03-14 11:05:36 +01:00
Noah Lancien
5bfc256b30 Accessibility on unveil-page done with Tanaguru (except colors) 2024-03-14 10:51:23 +01:00
Noah Lancien
437c23b77d Accessibility on homepage done with Tanaguru (except colors) 2024-03-14 09:26:25 +00:00
Alexis Gousseau
6707463e2d fix errors after merge of multiple branch 2024-03-13 17:49:14 +01:00
Alexis Gousseau
1d55d19fb9 fix purge sass in vite.config.ts 2024-03-13 17:24:49 +01:00
Jérémy Munsch
dd7639c803
Merge branch 'on-bouge-ensemble' into issue-fo 2024-03-13 16:38:15 +01:00
Jérémy Munsch
4979a23745
remove extensions files from .vscode 2024-03-13 16:33:02 +01:00
Vincent BRIDIER
2214a4294a
Merge branch 'trunk' 2023-10-16 12:35:31 +02:00
Vincent BRIDIER
b315da9d63
Merge branch 'develop' into trunk 2023-10-16 12:28:19 +02:00
Vincent BRIDIER
67fde446dc
Merge branch 'develop' into trunk 2023-10-16 12:12:59 +02:00
Vincent BRIDIER
d9c3a02fe4
Merge branch 'trunk' 2023-05-30 14:02:04 +02:00
Vincent BRIDIER
cab0866422
Merge branch 'develop' into trunk 2023-05-30 12:53:36 +02:00
Vincent BRIDIER
50b4ecfb43
Merge branch 'trunk' 2023-05-26 14:52:43 +02:00
Vincent BRIDIER
de6beb5cfe
Merge branch 'develop' into trunk 2023-05-26 14:44:40 +02:00
401 changed files with 22307 additions and 8399 deletions

View file

@ -61,8 +61,29 @@ VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# Sentry
SENTRY_LARAVEL_DSN=
# Matomo
MATOMO_SITE_ID=id
# MAILS
MAIL_CONTACT_REMARK="equipe.web@ldc.fr"
MAIL_CONTACT_SPONSORING="equipe.web@ldc.fr"
MAIL_CONTACT_SERVICE="equipe.web@ldc.fr"
MAIL_CONTACT_OTHER="equipe.web@ldc.fr"
# GOOGLE
# - RECAPTCHA
GOOGLE_RECAPTCHA_PUBLIC=
GOOGLE_RECAPTCHA_PRIVATE=
GOOGLE_RECAPTCHA_VERSION=
SAML2_DEFAULT_TENANT_UUID=
SAML2_SP_CERT_x509=
SAML2_SP_CERT_PRIVATEKEY=
SAML2_CONTACT_TECHNICAL_EMAIL=
# UWIL ADMIN SECURE
# - LIST SEPARATED WITH ',' (Required)
UWIL_ADMIN_SECURE_CIDR_LIST=""
# - LIST SEPARATED WITH ',' (Optional)
UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST=""

3
.gitignore vendored
View file

@ -23,6 +23,9 @@ Homestead.yaml
npm-debug.log
yarn-error.log
.npmrc
.zshrc
.npm/
.composer/
# Ignore public favicon
/public/android-chrome-192x192.png

View file

@ -1,13 +1,13 @@
include:
- project: "ldc-web/shared-ci"
ref: "main"
file: "lint/lint8.3.yml"
file: "lint/lint.yml"
- project: "ldc-web/shared-ci"
ref: "main"
file: "security/security8.3.yml"
file: "security/security.yml"
- project: "ldc-web/shared-ci"
ref: "main"
file: "build/build8.3.yml"
file: "build/docker-multistage.yml"
- project: "ldc-web/shared-ci"
ref: "main"
file: "test/test.yml"

2
.husky/commit-msg Normal file
View file

@ -0,0 +1,2 @@
#!/bin/sh
npx commitlint --config node_modules/@uwil/husky-config/commitlint.config.js --edit $1

View file

@ -1,20 +0,0 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"rvest.vs-code-prettier-eslint",
"onecentlin.laravel-extension-pack",
"johnpapa.vscode-peacock",
"xdebug.php-debug",
"neilbrayfield.php-docblocker",
"bmewburn.vscode-intelephense-client",
"valeryanm.vscode-phpsab",
"syler.sass-indented",
"sibiraj-s.vscode-scss-formatter",
"mrmlnc.vscode-scss",
"stylelint.vscode-stylelint",
"vue.vscode-typescript-vue-plugin",
"wscats.vue",
"vue.volar",
"misterj.vue-volar-extention-pack"
]
}

View file

@ -20,7 +20,7 @@
"commandCenter.border": "#e7e7e799"
},
"peacock.remoteColor": "#103251",
"intelephense.environment.phpVersion": "8.2.0",
"intelephense.environment.phpVersion": "8.3.0",
"intelephense.completion.fullyQualifyGlobalConstantsAndFunctions": true,
"intelephense.phpdoc.useFullyQualifiedNames": true
}

View file

@ -1,5 +1,46 @@
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/ldcweb-production-8.2:latest
COPY --chown=www-data:www-data . /app/srcs
FROM composer:2.8 AS vendor
ARG GITLAB_USER
ARG GITLAB_PASSWORD
COPY database/ database/
COPY composer.json composer.json
COPY composer.lock composer.lock
RUN composer config gitlab-token.lab.s-web.fr ${GITLAB_USER} ${GITLAB_PASSWORD}
RUN composer install \
--ignore-platform-reqs \
--no-interaction \
--no-plugins \
--no-scripts \
--no-dev \
--prefer-dist
FROM node:20.18 AS frontend
ARG GITLAB_PASSWORD
RUN mkdir -p /app/public/build
COPY package*.json tsconfig.json vite.config.ts .eslintrc.json .stylelintrc.json /app/
COPY resources/ /app/resources/
WORKDIR /app
RUN npm config set @ldc-web:registry https://lab.s-web.fr/api/v4/packages/npm/
RUN npm config set -- '//lab.s-web.fr/api/v4/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
RUN npm config set @uwil:registry https://lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/
RUN npm config set -- '//lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
RUN npm ci --no-audit --no-fund --loglevel=error && npm run prod
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
ARG USER=www-data
COPY --chown=${USER}:${USER} . /app/srcs
COPY --from=vendor --chown=${USER}:${USER} /app/vendor/ /app/srcs/vendor/
COPY --from=frontend --chown=${USER}:${USER} /app/public/build/ /app/srcs/public/build/
COPY --chown=${USER}:${USER} ./resources/favicon /app/srcs/public
USER root
RUN chmod -R 755 /app/srcs/storage
USER www-data
USER ${USER}

View file

@ -0,0 +1,46 @@
<?php
namespace App\Console\Commands;
use App\Jobs\CleanOldActivities as CleanOldActivitiesJob;
use Illuminate\Console\Command;
class CleanOldActivities extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:activity-logs:clean {--force : Delete all activity logs regardless of date.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clean all logs older than one year. Use --force to delete all logs.';
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$messageTitle = "<comment>activity logs</comment>";
$this->components->info("Cleaning {$messageTitle}...");
$force = $this->option('force');
if ($force && !$this->confirm('Are you sure you want to delete all activity logs ? This cannot be undone.')) {
$this->components->error("Clean of {$messageTitle} aborted.");
return;
}
(new CleanOldActivitiesJob(force: $force))->handle();
$messageContent = $force ? "All {$messageTitle} deleted" : "Old {$messageTitle} cleaned";
$this->components->success($messageContent);
}
}

View file

@ -0,0 +1,117 @@
<?php
namespace App\Console\Commands;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Str;
/**
* Artisan command to create a backend admin user.
*/
class MakeUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:make:user';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new backend admin user.';
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$this->components->info("Creating a new <comment>backend user</comment>...");
$firstName = $this->askValid(
'first_name',
'First name',
'Admin',
['required', 'min:3', 'max:255']
);
$lastName = $this->askValid(
'last_name',
'Last name',
'Saïtama',
['required', 'min:3', 'max:255']
);
$email = $this->askValid(
'email',
'Email',
'equipe.web@ldc.fr',
['required', 'unique:users,email', 'email:rfc,strict,dns,spoof,filter']
);
$role = $this->askRole();
$user = new User([
'first_name' => $firstName,
'last_name' => $lastName,
'email' => $email,
'role' => $role,
'published' => true,
'published_at' => Carbon::now(),
]);
$user->saveOrFail();
$this->components->success("User <comment>{$firstName} {$lastName}</comment> created successfully.");
}
/**
* Ask for a value and validate it, re-prompting on failure.
*
* @param string $field
* @param string $label
* @param string $default
* @param array<int, string> $rules
* @return string
*/
private function askValid(string $field, string $label, string $default, array $rules): string
{
try {
$value = $this->ask(sprintf("Type the wanted user %s", $label), $default);
$validator = Validator::make([$field => $value], [$field => $rules]);
$validator->validate();
return $value;
} catch (ValidationException $e) {
$this->components->error(
collect($e->errors())->flatten()->first()
);
return $this->askValid($field, $label, $default, $rules);
}
}
/**
* Ask for a role and return the corresponding RoleEnum.
*
* @return \App\Enums\Users\RoleEnum
*/
private function askRole(): \App\Enums\Users\RoleEnum
{
$options = collect([
RoleEnum::conceptor,
RoleEnum::admin,
RoleEnum::visitor,
])->mapWithKeys(fn(RoleEnum $role) => [
Str::ucFirst($role->label()) => $role
]);
/** @var string $choice */
$choice = $this->choice('Role', $options->keys()->all(), Str::ucFirst(RoleEnum::visitor->label()));
return $options->get($choice);
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace App\Console\Commands;
use App\Jobs\UpdatePlanificatedStatus as UpdatePlanificatedStatusJob;
use Illuminate\Console\Command;
class UpdatePlanificatedStatus extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:update-planificated-status';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update models planificated status.';
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
(new UpdatePlanificatedStatusJob())->handle();
$this->info('Models\' planificated status updated 👌');
}
}

View file

@ -1,236 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Str;
class UserCreate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:user:create';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a backend admin user';
/**
* The first name of the new user.
*
* @var string|null
*/
protected $first_name;
/**
* The last name of the new user.
*
* @var string|null
*/
protected $last_name;
/**
* The email of the new user.
*
* @var string|null
*/
protected $email;
/**
* The password of the new user.
*
* @var string|null
*/
protected $password;
/**
* The role of the new user.
*
* @var string|null
*/
protected $role;
/**
* Execute the console command.
*
* @return integer
*/
public function handle(): int
{
$this->first_name = null;
$this->addFirstName();
$this->last_name = null;
$this->addLastName();
$this->email = null;
$this->addEmail();
$this->password = null;
$this->addPassword();
$this->role = null;
$this->addRole();
$user = new User([
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'email' => $this->email,
'password' => $this->password,
'role' => $this->role,
'published' => true,
'published_at' => Carbon::now(),
]);
$user->saveOrFail();
$this->info('User created 👌');
return 0;
}
/**
* Add a first name to the user.
*
* @return void
*/
private function addFirstName(): void
{
while (is_null($this->first_name)) {
try {
$tmp = $this->ask('Type the wanted user first name', 'Admin');
$validator = Validator::make(['first_name' => $tmp], [
'first_name' => 'required|min:3|max:255'
]);
$validator->validate();
$this->first_name = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid first name %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
/**
* Add a last name to the user.
*
* @return void
*/
private function addLastName(): void
{
while (is_null($this->last_name)) {
try {
$tmp = $this->ask('Type the wanted user last name', 'Saïtama');
$validator = Validator::make(['last_name' => $tmp], [
'last_name' => 'required|min:3|max:255'
]);
$validator->validate();
$this->last_name = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid last_name %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
}
/**
* Add a role to the user.
*
* @return void
*/
private function addRole(): void
{
while (is_null($this->role)) {
try {
$tmp = $this->choice(
'Select his role',
[
Str::ucFirst(RoleEnum::conceptor->label()),
Str::ucFirst(RoleEnum::admin->label()),
Str::ucFirst(RoleEnum::visitor->label())
],
Str::ucFirst(RoleEnum::visitor->label()),
$maxAttempts = null,
$allowMultipleSelections = false
);
if ($tmp === Str::ucFirst(RoleEnum::conceptor->label())) {
$tmp = RoleEnum::conceptor;
}
if ($tmp === Str::ucFirst(RoleEnum::admin->label())) {
$tmp = RoleEnum::admin;
}
if ($tmp === Str::ucFirst(RoleEnum::visitor->label())) {
$tmp = RoleEnum::visitor;
}
$validator = Validator::make(['role' => $tmp], [
'role' => 'required'
]);
$validator->validate();
$this->role = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please choose from the selection %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
}

View file

@ -2,6 +2,8 @@
namespace App\Console;
use App\Jobs\CleanOldActivities;
use App\Jobs\UpdatePlanificatedStatus;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -13,8 +15,10 @@ class Kernel extends ConsoleKernel
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
protected function schedule(Schedule $schedule): void
{
$schedule->job(CleanOldActivities::class)->daily();
$schedule->job(UpdatePlanificatedStatus::class)->everyFiveMinutes();
}
/**
@ -22,7 +26,7 @@ class Kernel extends ConsoleKernel
*
* @return void
*/
protected function commands()
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');

View file

@ -14,7 +14,7 @@ enum ActivityLogsEventEnum: int
case deleted = 4;
/**
* Optionnal labels definition
* Optionnal labels definition.
*
* @phpstan-ignore-next-line
*/
@ -27,7 +27,7 @@ enum ActivityLogsEventEnum: int
/**
* Custom added classes definition
* Custom added classes definition.
*/
private const BOOTSTRAPCLASS = [
self::created->name => 'success',
@ -37,7 +37,7 @@ enum ActivityLogsEventEnum: int
];
/**
* Get Class
* Get Class.
*
* @return string
*/

View file

@ -9,9 +9,10 @@ enum CkEditorConfigName: int
use BaseEnum;
case minimal = 1;
case base = 2;
case basic = 2;
case advanced = 3;
/**
* Optionnal labels definition.
*
@ -19,7 +20,8 @@ enum CkEditorConfigName: int
*/
private const LABELS = [
self::minimal->name => 'minimal',
self::base->name => 'base',
self::basic->name => 'basic',
self::advanced->name => 'advanced',
];
}

View file

@ -357,9 +357,9 @@ enum Country: int
self::guatemala->name => 'Guatemala',
self::guernsey->name => 'Guernsey',
self::guinea->name => 'Guinea',
self::guineaBissau->name => 'GuineaBissau',
self::guineaBissau->name => 'Guinea Bissau',
self::guyana->name => 'Guyana',
self::haiti->name => 'Haiti',
self::haiti->name => 'Haïti',
self::heardIslandAndMcdonaldIslands->name => 'Heard Island and McDonald Islands',
self::holySeeVaticanCityState->name => 'Holy See (Vatican City State)',
self::honduras->name => 'Honduras',
@ -518,7 +518,7 @@ enum Country: int
/**
* Get Valid Shipping Countries
*
* @return array
* @return array<int, self>
*/
public static function validShippingCountries(): array
{
@ -544,7 +544,7 @@ enum Country: int
/**
* Get Valid Shipping Countries
*
* @return array
* @return array<int, self>
*/
public static function validBillingCountries(): array
{
@ -568,7 +568,7 @@ enum Country: int
/**
* Get Alpha 2 ISO code of valid shipping countries
*
* @return array
* @return array<int, string>
*/
public static function getValidShippingCountriesIsoAplha2Codes(): array
{
@ -578,7 +578,7 @@ enum Country: int
/**
* Get Alpha 2 ISO code of valid billing countries
*
* @return array
* @return array<int, string>
*/
public static function getValidBillingCountriesIsoAplha2Codes(): array
{
@ -586,21 +586,258 @@ enum Country: int
}
/**
* Custom added ISOCODES definition
* Custom added ISOCODES definition.
*/
private const ISOCODES = [
self::france->name => 'FR',
self::guadeloupe->name => 'GP',
self::martinique->name => 'MQ',
self::frenchGuiana->name => 'GF',
self::reunion->name => 'RE',
self::saintPierreAndMiquelon->name => 'PM',
self::mayotte->name => 'YT',
self::saintBarthelemy->name => 'BL',
self::saintMartinFrenchPart->name => 'MF',
self::wallisAndFutuna->name => 'WF',
self::frenchPolynesia->name => 'PF',
self::newCaledonia->name => 'NC',
self::afghanistan->name => 'AFG',
self::alandIslands->name => 'ALA',
self::albania->name => 'ALB',
self::algeria->name => 'DZA',
self::americanSamoa->name => 'ASM',
self::andorra->name => 'AND',
self::angola->name => 'AGO',
self::anguilla->name => 'AIA',
self::antarctica->name => 'AQ',
self::antiguaAndBarbuda->name => 'ATG',
self::argentina->name => 'ARG',
self::armenia->name => 'ARM',
self::aruba->name => 'ABW',
self::australia->name => 'AUS',
self::austria->name => 'AUT',
self::azerbaijan->name => 'AZE',
self::bahrain->name => 'BHR',
self::bahamas->name => 'BHS',
self::bangladesh->name => 'BGD',
self::barbados->name => 'BRB',
self::belarus->name => 'BLR',
self::belgium->name => 'BEL',
self::belize->name => 'BLZ',
self::benin->name => 'BEN',
self::bermuda->name => 'BMU',
self::bhutan->name => 'BTN',
self::boliviaPlurinationalStateOf->name => 'BOL',
self::bonaireSintEustatiusAndSaba->name => 'BES',
self::bosniaAndHerzegovina->name => 'BIH',
self::botswana->name => 'BWA',
self::bouvetIsland->name => 'BVT',
self::brazil->name => 'BRA',
self::britishIndianOceanTerritory->name => 'IOT',
self::bruneiDarussalam->name => 'BRN',
self::bulgaria->name => 'BGR',
self::burkinaFaso->name => 'BFA',
self::burundi->name => 'BDI',
self::cambodia->name => 'KHM',
self::cameroon->name => 'CMR',
self::canada->name => 'CAN',
self::capeVerde->name => 'CPV',
self::caymanIslands->name => 'CYM',
self::centralAfricanRepublic->name => 'CAF',
self::chad->name => 'TCD',
self::chile->name => 'CHL',
self::china->name => 'CHN',
self::christmasIsland->name => 'CXR',
self::cocosKeelingIslands->name => 'CCK',
self::colombia->name => 'COL',
self::comoros->name => 'COM',
self::congo->name => 'COG',
self::congoTheDemocraticRepublicOfThe->name => 'COD',
self::cookIslands->name => 'COK',
self::costaRica->name => 'CRI',
self::coteDivoire->name => 'CIV',
self::croatia->name => 'HRV',
self::cuba->name => 'CUB',
self::curacao->name => 'CUW',
self::cyprus->name => 'CYP',
self::czechRepublic->name => 'CZE',
self::denmark->name => 'DNK',
self::djibouti->name => 'DJI',
self::dominica->name => 'DMA',
self::dominicanRepublic->name => 'DOM',
self::ecuador->name => 'ECU',
self::egypt->name => 'EGY',
self::elSalvador->name => 'SLV',
self::equatorialGuinea->name => 'GNQ',
self::eritrea->name => 'ERI',
self::estonia->name => 'EST',
self::ethiopia->name => 'ETH',
self::falklandIslandsMalvinas->name => 'FLK',
self::faroeIslands->name => 'FRO',
self::fiji->name => 'FJI',
self::finland->name => 'FIN',
self::france->name => 'FRA',
self::frenchGuiana->name => 'GUF',
self::frenchPolynesia->name => 'PYF',
self::frenchSouthernTerritories->name => 'ATF',
self::gabon->name => 'GAB',
self::gambia->name => 'GMB',
self::georgia->name => 'GEO',
self::germany->name => 'DEU',
self::ghana->name => 'GHA',
self::gibraltar->name => 'GIB',
self::greece->name => 'GRC',
self::greenland->name => 'GRL',
self::grenada->name => 'GRD',
self::guadeloupe->name => 'GLP',
self::guam->name => 'GUM',
self::guatemala->name => 'GTM',
self::guernsey->name => 'GGY',
self::guinea->name => 'GIN',
self::guineaBissau->name => 'GNB',
self::guyana->name => 'GUY',
self::haiti->name => 'HTI',
self::heardIslandAndMcdonaldIslands->name => 'HMD',
self::holySeeVaticanCityState->name => 'VAT',
self::honduras->name => 'HND',
self::hongKong->name => 'HKG',
self::hungary->name => 'HUN',
self::iceland->name => 'ISL',
self::india->name => 'IND',
self::indonesia->name => 'IDN',
self::iranIslamicRepublicOf->name => 'IRN',
self::iraq->name => 'IRQ',
self::ireland->name => 'IRL',
self::isleOfMan->name => 'IMN',
self::israel->name => 'ISR',
self::italy->name => 'ITA',
self::jamaica->name => 'JAM',
self::japan->name => 'JPN',
self::jersey->name => 'JEY',
self::jordan->name => 'JOR',
self::kazakhstan->name => 'KAZ',
self::kenya->name => 'KEN',
self::kiribati->name => 'KIR',
self::koreaDemocraticPeoplesRepublicOf->name => 'PRK',
self::koreaRepublicOf->name => 'KOR',
self::kuwait->name => 'KWT',
self::kyrgyzstan->name => 'KGZ',
self::laoPeoplesDemocraticRepublic->name => 'LAO',
self::latvia->name => 'LVA',
self::lebanon->name => 'LBN',
self::lesotho->name => 'LSO',
self::liberia->name => 'LBR',
self::libya->name => 'LBY',
self::liechtenstein->name => 'LIE',
self::lithuania->name => 'LTU',
self::luxembourg->name => 'LUX',
self::macao->name => 'MAC',
self::macedoniaTheFormerYugoslavRepublicOf->name => 'MKD',
self::madagascar->name => 'MDG',
self::malawi->name => 'MWI',
self::malaysia->name => 'MYS',
self::maldives->name => 'MDV',
self::mali->name => 'MLI',
self::malta->name => 'MLT',
self::marshallIslands->name => 'MHL',
self::martinique->name => 'MTQ',
self::mauritania->name => 'MRT',
self::mauritius->name => 'MUS',
self::mayotte->name => 'MYT',
self::mexico->name => 'MEX',
self::micronesiaFederatedStatesOf->name => 'FSM',
self::moldovaRepublicOf->name => 'MDA',
self::monaco->name => 'MCO',
self::mongolia->name => 'MNG',
self::montenegro->name => 'MNE',
self::montserrat->name => 'MSR',
self::morocco->name => 'MAR',
self::mozambique->name => 'MOZ',
self::myanmar->name => 'MMR',
self::namibia->name => 'NAM',
self::nauru->name => 'NRU',
self::nepal->name => 'NPL',
self::netherlands->name => 'NLD',
self::newCaledonia->name => 'NCL',
self::newZealand->name => 'NZL',
self::nicaragua->name => 'NIC',
self::niger->name => 'NER',
self::nigeria->name => 'NGA',
self::niue->name => 'NIU',
self::norfolkIsland->name => 'NFK',
self::northernMarianaIslands->name => 'MNP',
self::norway->name => 'NOR',
self::oman->name => 'OMN',
self::pakistan->name => 'PAK',
self::palau->name => 'PLW',
self::palestineStateOf->name => 'PSE',
self::panama->name => 'PAN',
self::papuaNewGuinea->name => 'PNG',
self::paraguay->name => 'PRY',
self::peru->name => 'PER',
self::philippines->name => 'PHL',
self::pitcairn->name => 'PCN',
self::poland->name => 'POL',
self::portugal->name => 'PRT',
self::puertoRico->name => 'PRI',
self::qatar->name => 'QAT',
self::reunion->name => 'REU',
self::romania->name => 'ROU',
self::russianFederation->name => 'RUS',
self::rwanda->name => 'RWA',
self::saintBarthelemy->name => 'BLM',
self::saintHelenaAscensionAndTristanDaCunha->name => 'SHN',
self::saintKittsAndNevis->name => 'KNA',
self::saintLucia->name => 'LCA',
self::saintMartinFrenchPart->name => 'MAF',
self::saintPierreAndMiquelon->name => 'SPM',
self::saintVincentAndTheGrenadines->name => 'VCT',
self::samoa->name => 'WSM',
self::sanMarino->name => 'SMR',
self::saoTomeAndPrincipe->name => 'STP',
self::saudiArabia->name => 'SAU',
self::senegal->name => 'SEN',
self::serbia->name => 'SRB',
self::seychelles->name => 'SYC',
self::sierraLeone->name => 'SLE',
self::singapore->name => 'SGP',
self::sintMaartenDutchPart->name => 'SXM',
self::slovakia->name => 'SVK',
self::slovenia->name => 'SVN',
self::solomonIslands->name => 'SLB',
self::somalia->name => 'SOM',
self::southAfrica->name => 'ZAF',
self::southGeorgiaAndTheSouthSandwichIslands->name => 'SGS',
self::southSudan->name => 'SSD',
self::spain->name => 'ESP',
self::sriLanka->name => 'LKA',
self::sudan->name => 'SDN',
self::suriname->name => 'SUR',
self::svalbardAndJanMayen->name => 'SJM',
self::swaziland->name => 'SWZ',
self::sweden->name => 'SWE',
self::switzerland->name => 'CHE',
self::syrianArabRepublic->name => 'SYR',
self::taiwanProvinceOfChina->name => 'TWN',
self::tajikistan->name => 'TJK',
self::tanzaniaUnitedRepublicOf->name => 'TZA',
self::thailand->name => 'THA',
self::timorLeste->name => 'TLS',
self::togo->name => 'TGO',
self::tokelau->name => 'TKL',
self::tonga->name => 'TON',
self::trinidadAndTobago->name => 'TTO',
self::tunisia->name => 'TUN',
self::turkey->name => 'TUR',
self::turkmenistan->name => 'TKM',
self::turksAndCaicosIslands->name => 'TCA',
self::tuvalu->name => 'TUV',
self::uganda->name => 'UGA',
self::ukraine->name => 'UKR',
self::unitedArabEmirates->name => 'ARE',
self::unitedKingdom->name => 'GBR',
self::unitedStates->name => 'USA',
self::unitedStatesMinorOutlyingIslands->name => 'UMI',
self::uruguay->name => 'URY',
self::uzbekistan->name => 'UZB',
self::vanuatu->name => 'VUT',
self::venezuelaBolivarianRepublicOf->name => 'VEN',
self::vietNam->name => 'VNM',
self::virginIslandsBritish->name => 'VGB',
self::virginIslandsUs->name => 'VIR',
self::wallisAndFutuna->name => 'WLF',
self::westernSahara->name => 'ESH',
self::yemen->name => 'YEM',
self::zambia->name => 'ZMB',
self::zimbabwe->name => 'ZWE',
];
/**

View file

@ -13,30 +13,32 @@ enum PageSectionEnum: int
case home_team = 3;
case home_life = 4;
case unveil_pole = 5;
case unveil_local = 6;
case unveil_sites = 7;
case unveil_history = 8;
case unveil_commitments = 9;
case hire_life = 10;
case hire_formation = 11;
case hire_grow = 12;
case hire_parity = 13;
case hire_find = 14;
case commit_ambition = 15;
case commit_breeding = 16;
case commit_living = 17;
case commit_respect_earth = 18;
case commit_feed = 19;
case commit_commitments = 20;
case move_life = 21;
case move_commitments = 22;
case produce_local = 23;
case produce_gms = 24;
case produce_rhd = 25;
case produce_export = 26;
case produce_quality = 27;
case produce_linking = 28;
case listening_study = 29;
case unveil_missions = 6;
case unveil_local = 7;
case unveil_sites = 8;
case unveil_history = 9;
case unveil_commitments = 10;
case hire_life = 11;
case hire_formation = 12;
case hire_grow = 13;
case hire_parity = 14;
case hire_find = 15;
case commit_ambition = 16;
case commit_breeding = 17;
case commit_living = 18;
case commit_respect_earth = 19;
case commit_feed = 20;
case commit_commitments = 21;
case move_life = 22;
case move_commitments = 23;
case produce_local = 24;
case produce_gms = 25;
case produce_rhd = 26;
case produce_export = 27;
case produce_quality = 28;
case produce_linking = 29;
case listening_study = 30;
case produce_networks = 31;
/**
* Optionnal labels definition.
@ -49,6 +51,7 @@ enum PageSectionEnum: int
self::home_team->name => 'L\'équipe VOLENA',
self::home_life->name => 'La vie chez VOLENA',
self::unveil_pole->name => 'Le Pôle Volena',
self::unveil_missions->name => 'Nos Missions',
self::unveil_local->name => 'Notre Filière Locale',
self::unveil_sites->name => 'Nos Sites',
self::unveil_history->name => 'Histoire',
@ -73,6 +76,7 @@ enum PageSectionEnum: int
self::produce_quality->name => 'Qualité',
self::produce_linking->name => 'Liens',
self::listening_study->name => 'On étudie',
self::produce_networks->name => 'Nos réseaux',
];
/**
@ -96,6 +100,7 @@ enum PageSectionEnum: int
self::commit_feed,
self::move_commitments,
self::produce_linking => true,
self::unveil_missions,
self::unveil_local,
self::unveil_sites,
self::unveil_history,
@ -111,7 +116,8 @@ enum PageSectionEnum: int
self::produce_rhd,
self::produce_export,
self::produce_quality,
self::listening_study => false,
self::listening_study,
self::produce_networks => false,
}; //end match
}
@ -129,8 +135,9 @@ enum PageSectionEnum: int
self::home_life,
self::unveil_sites,
self::unveil_history,
self::unveil_commitments => \App\Enums\CkEditorConfigName::base->label(),
self::unveil_commitments => \App\Enums\CkEditorConfigName::basic->label(),
self::unveil_pole,
self::unveil_missions,
self::unveil_local,
self::hire_life,
self::hire_formation,
@ -151,7 +158,8 @@ enum PageSectionEnum: int
self::produce_quality,
self::listening_study => \App\Enums\CkEditorConfigName::advanced->label(),
self::produce_linking,
self::hire_grow, => null,
self::hire_grow,
self::produce_networks => null,
}; //end match
}
}

View file

@ -30,4 +30,73 @@ enum SpeciesEnum: int
self::guinea_fowl->name => 'Pintade',
self::rooster->name => 'Coq',
];
/**
* Pictures paths.
*/
private const PICTURES = [
self::chicken->name => 'resources/assets/images/pictos/chicken.jpg',
self::turkey->name => 'resources/assets/images/pictos/turkey.jpg',
self::hen->name => 'resources/assets/images/pictos/hen_and_rooster.jpg',
self::duck->name => 'resources/assets/images/pictos/duck.jpg',
self::rabbit->name => 'resources/assets/images/pictos/rabbit.jpg',
self::guinea_fowl->name => 'resources/assets/images/pictos/guinea_fowl.jpg',
self::rooster->name => 'resources/assets/images/pictos/hen_and_rooster.jpg',
];
/**
* Get picture path
*
* @return string
*/
public function picture(): string
{
return self::PICTURES[$this->name];
}
/**
* Alt attributes for pictures.
*/
private const ALTS = [
self::chicken->name => 'Pictogramme pour la catégorie \'poulet\'',
self::turkey->name => 'Pictogramme pour la catégorie \'dinde\'',
self::hen->name => 'Pictogramme pour la catégorie \'poule\'',
self::duck->name => 'Pictogramme pour la catégorie \'canard\'',
self::rabbit->name => 'Pictogramme pour la catégorie \'lapin\'',
self::guinea_fowl->name => 'Pictogramme pour la catégorie \'pintade\'',
self::rooster->name => 'Pictogramme pour la catégorie \'coq\'',
];
/**
* Get picture alt attribute.
*
* @return string
*/
public function alt(): string
{
return self::ALTS[$this->name];
}
/**
* Alt attributes for pictures.
*/
private const TITLES = [
self::chicken->name => 'Pictogramme pour la catégorie \'poulet\'',
self::turkey->name => 'Pictogramme pour la catégorie \'dinde\'',
self::hen->name => 'Pictogramme pour la catégorie \'poule\'',
self::duck->name => 'Pictogramme pour la catégorie \'canard\'',
self::rabbit->name => 'Pictogramme pour la catégorie \'lapin\'',
self::guinea_fowl->name => 'Pictogramme pour la catégorie \'pintade\'',
self::rooster->name => 'Pictogramme pour la catégorie \'coq\'',
];
/**
* Get picture alt attribute.
*
* @return string
*/
public function title(): string
{
return self::TITLES[$this->name];
}
}

View file

@ -11,6 +11,7 @@ enum SliderTypeEnum: int
case home = 1;
case better_life = 2;
case respect_earth = 3;
case team = 4;
/**
* Optionnal labels definition.
@ -21,5 +22,6 @@ enum SliderTypeEnum: int
self::home->name => 'Accueil',
self::better_life->name => 'Mieux vivre',
self::respect_earth->name => 'Respecter la terre',
self::team->name => 'Nous rejoindre',
];
}

View file

@ -40,7 +40,7 @@ enum StaticPageType: int
/**
* Get the enums for the page which contains sections.
*
* @return array
* @return array<int, self>
*/
public static function containsSection(): array
{
@ -59,20 +59,40 @@ enum StaticPageType: int
* Does the static page need to fill its 'content' column ?
*
* @return boolean
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function containsContent(): bool
{
// @phpcs:enable
return match ($this) {
self::contact,
self::legals,
self::contact => false,
self::legals => true,
self::confidentiality => true,
self::home,
self::home => false,
self::unveil => false,
self::we_hire => false,
self::we_commit => false,
self::we_move => false,
self::we_produce => false,
self::we_listen => false,
};
}
/**
* Does the static page need to fill its 'picture' column ?
*
* @return boolean
*/
public function containsBanner(): bool
{
return match ($this) {
self::unveil,
self::we_hire,
self::we_commit,
self::we_move,
self::we_produce,
self::we_listen => false,
self::we_listen => true,
default => false,
};
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Enums;
use App\Traits\Enums\BaseEnum;
enum StickiesColorEnum: int
{
use BaseEnum;
case primary = 1;
case secondary = 2;
case tertiary = 3;
case quad = 4;
case quint = 5;
case sixt = 6;
/**
* Optionnal labels definition.
*
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::primary->name => 'Primary',
self::secondary->name => 'Secondary',
self::tertiary->name => 'Tertiary',
self::quad->name => 'Quad',
self::quint->name => 'Quint',
self::sixt->name => 'Sixt',
];
}

View file

@ -33,7 +33,7 @@ enum PictoEnum: int
* Pictures paths.
*/
private const PICTURES = [
self::none->name => '',
self::none->name => 'resources/assets/images/pictos/none.jpg',
self::danger->name => 'resources/assets/images/pictos/danger.png',
self::respect_earth->name => 'resources/assets/images/pictos/respect_earth.png',
self::breeding->name => 'resources/assets/images/pictos/breeding.png',
@ -42,7 +42,7 @@ enum PictoEnum: int
];
/**
* Get picture path
* Get picture path.
*
* @return string
*/
@ -55,7 +55,7 @@ enum PictoEnum: int
* Alt attributes for pictures.
*/
private const ALTS = [
self::none->name => '',
self::none->name => 'Logo Volena',
self::danger->name => 'Pictogramme pour la catégorie \'Danger\'',
self::respect_earth->name => 'Pictogramme pour la catégorie \'Respecter la terre\'',
self::breeding->name => 'Pictogramme pour la catégorie \'Elever durablement\'',
@ -64,7 +64,7 @@ enum PictoEnum: int
];
/**
* Get picture alt attribute
* Get picture alt attribute.
*
* @return string
*/
@ -78,7 +78,7 @@ enum PictoEnum: int
* Alt attributes for pictures.
*/
private const TITLES = [
self::none->name => '',
self::none->name => 'Logo Volena',
self::danger->name => 'Pictogramme pour la catégorie \'Danger\'',
self::respect_earth->name => 'Pictogramme pour la catégorie \'Respecter la terre\'',
self::breeding->name => 'Pictogramme pour la catégorie \'Elever durablement\'',
@ -87,7 +87,7 @@ enum PictoEnum: int
];
/**
* Get picture alt attribute
* Get picture alt attribute.
*
* @return string
*/

View file

@ -29,6 +29,9 @@ enum TypeEnum: int
self::hire->name => 'On Embauche',
];
/**
* Optionnal labels definition.
*/
private const COLORS = [
self::breeding->name => 'tertiary',
self::better_life->name => 'quad',
@ -39,7 +42,7 @@ enum TypeEnum: int
];
/**
* Get color name
* Get color name.
*
* @return string
*/

View file

@ -21,8 +21,7 @@ class ActivityLogController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
$this->authorize('isConceptor');
/** @var \Illuminate\Database\Eloquent\Builder $query */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\ActivityLog> $query */
$query = ActivityLog::query()->with('user');
/** @var string $search Search field */
@ -56,7 +55,7 @@ class ActivityLogController extends Controller
*/
public function show(ActivityLog $activity_log): \Illuminate\Contracts\View\View
{
$this->authorize('isConceptor');
/** @var \Illuminate\Database\Eloquent\Model $targetModelClass */
$targetModelClass = $activity_log->model_class;
$targetModel = $activity_log->model_class::where(
(new $targetModelClass())->getRouteKeyName(),

View file

@ -0,0 +1,194 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Aisles\StoreAisleRequest;
use App\Http\Requests\Bo\Aisles\UpdateAisleRequest;
use App\Models\Aisle;
use App\Models\Network;
use App\Traits\Controllers\UpdateModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class AisleController extends Controller
{
use UpdateModelOrder;
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Aisle::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Aisle> $aisleModels */
$aisleModels = Aisle::query()->with('network');
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Network> $networkModels */
$networkModels = Network::query()->where('published', true)->get();
$selectedNetwork = intval($request->network);
$aisleModels = $aisleModels->when($selectedNetwork, function ($query) use ($selectedNetwork) {
$query->where('network_id', $selectedNetwork);
});
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$aisleModels,
$search,
null,
'name',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.name')),
]);
/** Sort columns with a query */
$this->sortQuery($aisleModels);
/** Custom pagination */
$aisleModels = $this->paginate($aisleModels);
return view(
'bo.pages.aisles.index',
compact(
'aisleModels',
'networkModels',
'selectedNetwork',
'search',
'searchFields'
)
);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Contracts\View\View
*/
public function create(Aisle $aisle): \Illuminate\Contracts\View\View
{
$networkModels = Network::all();
return view('bo.pages.aisles.create', [
'aisleModel' => $aisle,
'networkModels' => $networkModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Aisles\StoreAisleRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreAisleRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$aisle = new Aisle();
$aisle->fill($request->validated());
if ($aisle->saveOrFail()) {
return redirect()->route('bo.aisles.edit', $aisle)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Contracts\View\View
*/
public function edit(Aisle $aisle): \Illuminate\Contracts\View\View
{
$networkModels = Network::all();
return view('bo.pages.aisles.edit', [
'aisleModel' => $aisle,
'networkModels' => $networkModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Aisles\UpdateAisleRequest $request
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateAisleRequest $request, Aisle $aisle): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $aisle) {
$aisle->fill($request->validated());
if ($aisle->saveOrFail()) {
return redirect()->route('bo.aisles.edit', $aisle)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
}
return redirect()->route('bo.aisles.edit', $aisle)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Aisle $aisle): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($aisle) {
if ($aisle->deleteOrFail()) {
return redirect()->route('bo.aisles.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
});
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Aisle $aisle): \Illuminate\Contracts\View\View
{
return $this->create($aisle->replicate());
}
}

View file

@ -3,8 +3,6 @@
namespace App\Http\Controllers\Bo\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@ -28,7 +26,7 @@ class LoginController extends Controller
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard(): StatefulGuard
protected function guard(): \Illuminate\Contracts\Auth\StatefulGuard
{
return Auth::guard('backend');
}
@ -38,7 +36,7 @@ class LoginController extends Controller
*
* @return \Illuminate\Contracts\View\View
*/
public function showLoginForm(): View
public function showLoginForm(): \Illuminate\Contracts\View\View
{
return view('bo.auth.login');
}
@ -59,7 +57,7 @@ class LoginController extends Controller
* @param \Illuminate\Http\Request $request
* @return boolean
*/
protected function attemptLogin(Request $request)
protected function attemptLogin(Request $request): bool
{
$credentials = $this->credentials($request);
// * Attempt login only using published users.

View file

@ -3,7 +3,6 @@
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;
@ -16,7 +15,7 @@ class ResetPasswordController extends Controller
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard(): StatefulGuard
protected function guard(): \Illuminate\Contracts\Auth\StatefulGuard
{
return Auth::guard('backend');
}

View file

@ -0,0 +1,176 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Brands\StoreBrandRequest;
use App\Http\Requests\Bo\Brands\UpdateBrandRequest;
use App\Models\Aisle;
use App\Models\Brand;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class BrandController extends Controller
{
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Brand::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Brand> $brandModels */
$brandModels = Brand::query()->with('aisle');
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$brandModels,
$search,
null,
'name',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.name')),
]);
/** Sort columns with a query */
$this->sortQuery($brandModels);
/** Custom pagination */
$brandModels = $this->paginate($brandModels);
return view('bo.pages.brands.index', compact('brandModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function create(Brand $brand): \Illuminate\Contracts\View\View
{
$aisleModels = Aisle::all();
return view('bo.pages.brands.create', [
'brandModel' => $brand,
'aisleModels' => $aisleModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\StoreBrandRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreBrandRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$brand = new Brand();
$brand->fill($request->validated());
if ($brand->saveOrFail()) {
return redirect()->route('bo.brands.edit', $brand)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function edit(Brand $brand): \Illuminate\Contracts\View\View
{
$aisleModels = Aisle::all();
return view('bo.pages.brands.edit', [
'brandModel' => $brand,
'aisleModels' => $aisleModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\UpdateBrandRequest $request
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateBrandRequest $request, Brand $brand): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $brand) {
$brand->fill($request->validated());
if ($brand->saveOrFail()) {
return redirect()->route('bo.brands.edit', $brand)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
}
return redirect()->route('bo.brands.edit', $brand)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Brand $brand): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($brand) {
if ($brand->deleteOrFail()) {
return redirect()->route('bo.brands.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
});
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Brand $brand): \Illuminate\Contracts\View\View
{
return $this->create($brand->replicate());
}
}

View file

@ -0,0 +1,228 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Carousels\StoreCarouselRequest;
use App\Http\Requests\Bo\Carousels\UpdateCarouselRequest;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Carousel;
use App\Models\Section;
use App\Traits\Controllers\UpdateModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class CarouselController extends Controller
{
use UpdateModelOrder;
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Carousel::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Carousel> $carouselModels */
$carouselModels = Carousel::query()->with('section');
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Section> $sectionModels */
$sectionModels = Section::query()->whereHas('carousels')->get();
$selectedSection = intval($request->section);
$carouselModels = $carouselModels->when($selectedSection, function ($query) use ($selectedSection) {
$query->where('section_id', $selectedSection);
});
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$carouselModels,
$search,
null,
'title',
);
}
$searchFields = \implode(', ', [
Str::ucFirst(trans('validation.attributes.title')),
]);
/** Sort columns with a query */
$this->sortQuery($carouselModels);
/** Custom pagination */
$carouselModels = $this->paginate($carouselModels);
return view('bo.pages.carousels.index', compact(
'carouselModels',
'sectionModels',
'selectedSection',
'search',
'searchFields'
));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Carousel $carousel
* @return \Illuminate\Contracts\View\View
*/
public function create(Carousel $carousel): \Illuminate\Contracts\View\View
{
$sectionModels = Section::all();
return view('bo.pages.carousels.create', [
'carouselModel' => $carousel,
'sectionModels' => $sectionModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Carousels\StoreCarouselRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreCarouselRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$carousel = new Carousel();
$carousel->fill($request->validated());
if (!Arr::exists($request->validated(), 'media')) {
$carousel->media = [];
}
// Set the new pictures files in the pictures array.
collect($request->only(['media.pictures.*.path']))
->each(
function (mixed $value, string $attribute) use ($carousel) {
foreach ($value['pictures']['*']['path'] as $index => $file) {
if ($file instanceof \Illuminate\Http\UploadedFile) {
$carousel->setAttribute(
"{$attribute}->pictures->{$index}->path",
FileStorageHelper::storeFile($carousel, $file, true)
);
}
}
}
);
if ($carousel->saveOrFail()) {
return redirect()->route('bo.carousels.edit', $carousel)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans_choice('models.classes.carousel', 1))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans_choice('models.classes.carousel', 1))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Carousel $carousel
* @return \Illuminate\Contracts\View\View
*/
public function edit(Carousel $carousel): \Illuminate\Contracts\View\View
{
$sectionModels = Section::all();
return view('bo.pages.carousels.edit', [
'carouselModel' => $carousel,
'sectionModels' => $sectionModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Carousels\UpdateCarouselRequest $request
* @param \App\Models\Carousel $carousel
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateCarouselRequest $request, Carousel $carousel): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $carousel) {
$carousel->fill($request->validated());
if (!Arr::exists($request->validated(), 'media')) {
$carousel->media = [];
}
// Set the new pictures files in the pictures array.
collect($request->only(['media.pictures.*.path']))
->each(
function (mixed $value, string $attribute) use ($carousel) {
foreach ($value['pictures']['*']['path'] as $index => $file) {
if ($file instanceof \Illuminate\Http\UploadedFile) {
$carousel->setAttribute(
"{$attribute}->pictures->{$index}->path",
FileStorageHelper::storeFile($carousel, $file, true)
);
}
}
}
);
if ($carousel->saveOrFail()) {
return redirect()->route('bo.carousels.edit', $carousel)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.carousel', 1))
]));
}
return redirect()->route('bo.carousels.edit', $carousel)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.carousel', 1))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Carousel $carousel
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Carousel $carousel): \Illuminate\Http\RedirectResponse
{
if ($carousel->deleteOrFail()) {
return redirect()->route('bo.carousels.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.carousel', 1))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.carousel', 1))
]));
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Carousel $carousel
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Carousel $carousel): \Illuminate\Contracts\View\View
{
return $this->create($carousel->replicate());
}
}

View file

@ -3,16 +3,15 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\View\View;
class DashboardController extends Controller
{
/**
* Dashboard Page
* Dashboard Page.
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): View
public function index(): \Illuminate\Contracts\View\View
{
return view('bo.pages.dashboard');
}

View file

@ -28,7 +28,7 @@ class HistoricalMilestoneController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $historicalMilestoneModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\HistoricalMilestone> $historicalMilestoneModels */
$historicalMilestoneModels = HistoricalMilestone::query();
/** @var string $search Search field */
@ -85,12 +85,12 @@ class HistoricalMilestoneController extends Controller
if ($historicalMilestone->saveOrFail()) {
return redirect()->route('bo.historicalmilestones.edit', $historicalMilestone)
->with('success', __('crud.messages.has_been_created', [
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans_choice('models.classes.historicalMilestone', 1))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans_choice('models.classes.historicalMilestone', 1))
]));
});
@ -123,12 +123,12 @@ class HistoricalMilestoneController extends Controller
if ($historicalMilestone->saveOrFail()) {
return redirect()->route('bo.historicalmilestones.edit', $historicalMilestone)
->with('success', __('crud.messages.has_been_updated', [
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.historicalMilestone', 1))
]));
}
return redirect()->route('bo.historicalmilestones.edit', $historicalMilestone)
->with('error', __('crud.messages.cannot_be_updated', [
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.historicalMilestone', 1))
]));
});
@ -144,12 +144,12 @@ class HistoricalMilestoneController extends Controller
{
if ($historicalMilestone->deleteOrFail()) {
return redirect()->route('bo.historicalmilestones.index')
->with('success', __('crud.messages.has_been_deleted', [
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.historicalMilestone', 1))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.historicalMilestone', 1))
]));
}

View file

@ -28,7 +28,7 @@ class JobVideoController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $jobVideoModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\JobVideo> $jobVideoModels */
$jobVideoModels = JobVideo::query();
/** @var string $search Search field */
@ -85,12 +85,12 @@ class JobVideoController extends Controller
if ($jobVideo->saveOrFail()) {
return redirect()->route('bo.jobvideos.edit', $jobVideo)
->with('success', __('crud.messages.has_been_created', [
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans_choice('models.classes.job_video', 1))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans_choice('models.classes.job_video', 1))
]));
});
@ -123,12 +123,12 @@ class JobVideoController extends Controller
if ($jobVideo->saveOrFail()) {
return redirect()->route('bo.jobvideos.edit', $jobVideo)
->with('success', __('crud.messages.has_been_updated', [
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.job_video', 1))
]));
}
return redirect()->route('bo.jobvideos.edit', $jobVideo)
->with('error', __('crud.messages.cannot_be_updated', [
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.job_video', 1))
]));
});
@ -144,12 +144,12 @@ class JobVideoController extends Controller
{
if ($jobVideo->deleteOrFail()) {
return redirect()->route('bo.jobvideos.index')
->with('success', __('crud.messages.has_been_deleted', [
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.job_video', 1))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.job_video', 1))
]));
}

View file

@ -28,11 +28,11 @@ class LogoController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $logoModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Logo> $logoModels */
$logoModels = Logo::query();
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$logoModels,
@ -83,13 +83,13 @@ class LogoController extends Controller
if ($logo->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.logos.edit', $logo)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.logo'))
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.logo'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.logo'))
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.logo'))
]));
});
}
@ -117,13 +117,13 @@ class LogoController extends Controller
return DB::transaction(function () use ($request, $logo) {
if ($logo->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.logos.edit', $logo)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.logo'))
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.logo'))
]));
}
return redirect()->route('bo.logos.edit', $logo)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.logo'))
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.logo'))
]));
});
}
@ -138,13 +138,13 @@ class LogoController extends Controller
{
if ($logo->deleteOrFail()) {
return redirect()->route('bo.logos.index')
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.logo'))
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.logo'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.logo'))
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.logo'))
]));
}

View file

@ -0,0 +1,171 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Networks\StoreNetworkRequest;
use App\Http\Requests\Bo\Networks\UpdateNetworkRequest;
use App\Models\Network;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class NetworkController extends Controller
{
use ChangesModelOrder;
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Network::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Network> $networkModels */
$networkModels = Network::query();
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$networkModels,
$search,
null,
'name',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.name')),
]);
/** Sort columns with a query */
$this->sortQuery($networkModels);
/** Custom pagination */
$networkModels = $this->paginate($networkModels);
return view('bo.pages.networks.index', compact('networkModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Network $network
* @return \Illuminate\Contracts\View\View
*/
public function create(Network $network): \Illuminate\Contracts\View\View
{
return view('bo.pages.networks.create', [
'networkModel' => $network,
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Networks\StoreNetworkRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreNetworkRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$network = new Network();
$network->fill($request->validated());
if ($network->saveOrFail()) {
return redirect()->route('bo.networks.edit', $network)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Network $network
* @return \Illuminate\Contracts\View\View
*/
public function edit(Network $network): \Illuminate\Contracts\View\View
{
return view('bo.pages.networks.edit', [
'networkModel' => $network,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Networks\UpdateNetworkRequest $request
* @param \App\Models\Network $network
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateNetworkRequest $request, Network $network): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $network) {
$network->fill($request->validated());
if ($network->saveOrFail()) {
return redirect()->route('bo.networks.edit', $network)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
}
return redirect()->route('bo.networks.edit', $network)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Network $network
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Network $network): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($network) {
if ($network->deleteOrFail()) {
return redirect()->route('bo.networks.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
});
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Network $network
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Network $network): \Illuminate\Contracts\View\View
{
return $this->create($network->replicate());
}
}

View file

@ -33,11 +33,11 @@ class NewsController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $newsModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\News> $newsModels */
$newsModels = News::query();
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$newsModels,
@ -88,13 +88,13 @@ class NewsController extends Controller
if ($news->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.news.edit', $news)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.news'))
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.news'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.news'))
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.news'))
]));
});
}
@ -122,13 +122,13 @@ class NewsController extends Controller
return DB::transaction(function () use ($request, $news) {
if ($news->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.news.edit', $news)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.news'))
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.news'))
]));
}
return redirect()->route('bo.news.edit', $news)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.news'))
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.news'))
]));
});
}
@ -143,13 +143,13 @@ class NewsController extends Controller
{
if ($news->deleteOrFail()) {
return redirect()->route('bo.news.index')
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.news'))
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.news'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.news'))
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.news'))
]));
}

View file

@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Sections\UpdateSectionRequest;
use App\Models\Section;
use App\Models\StaticPage;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
@ -29,7 +30,7 @@ class SectionController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $query */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Section> $query */
$query = Section::query()->with('page');
// Filter by related page if requested.
@ -48,7 +49,7 @@ class SectionController extends Controller
}
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$query,
@ -88,25 +89,63 @@ class SectionController extends Controller
* @param \App\Models\Section $section
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateSectionRequest $request, Section $section): \Illuminate\Http\RedirectResponse
public function update(UpdateSectionRequest $request, Section $section): RedirectResponse
{
return DB::transaction(function () use ($request, $section) {
$section->fill(array_replace_recursive(
\json_decode(\json_encode($section->toArray()), true),
$request->validated()
));
$encoded = json_encode($section->toArray());
if ($encoded === false) {
return redirect()->back()->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.section'))
]));
}
/** @var array<string, mixed> $data */
$data = json_decode($encoded, true);
$section->fill(array_replace_recursive($data, $request->validated()));
if ($section->saveOrFail()) {
return redirect()->route('bo.sections.edit', $section)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.section'))
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.section'))
]));
}
return redirect()->route('bo.sections.edit', $section)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.section'))
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.section'))
]));
});
}
/**
* Section add PartPiece
*
* @param \App\Models\Section $section
* @return \Illuminate\Http\RedirectResponse
*/
public function addPartPiece(Section $section): RedirectResponse
{
$section->addPartPiece();
$section->saveOrFail();
return response()->redirectToRoute('bo.sections.edit', $section)
->with('success', trans('Partie ajouté'));
}
/**
* Section remove PartPiece
*
* @param \App\Models\Section $section
* @param integer $index
* @return \Illuminate\Http\RedirectResponse
*/
public function removePartPiece(Section $section, int $index): RedirectResponse
{
$count = $section->removePartPiece($index);
$section->saveOrFail();
$response = response()->redirectToRoute('bo.sections.edit', $section);
if ($count) {
$response->with('error', trans('Partie enlevé'));
} else {
$response->with('info', trans('Aucune partie enlevé'));
}
return $response;
}
}

View file

@ -32,25 +32,23 @@ class SiteController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $siteModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Site> $siteModels */
$siteModels = Site::query();
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$siteModels,
$search,
null,
'title',
'introduction',
'content',
'name',
'description',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.title')),
trans('validation.custom.introduction'),
trans('validation.attributes.content'),
Str::ucfirst(trans('validation.attributes.name')),
trans('validation.attributes.description'),
]);
/** Sort columns with a query */
@ -92,15 +90,17 @@ class SiteController extends Controller
$site->fill($request->safe()->except(['logos']));
if ($site->saveOrFail()) {
$site->logos()->attach(collect($request->validated('logos'))->pluck('id'));
/** @var array<int, array<string, mixed>> $logos */
$logos = $request->validated('logos') ?? [];
$site->logos()->attach(collect($logos)->pluck('id'));
return redirect()->route('bo.sites.edit', $site)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.site'))
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.site'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.site'))
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.site'))
]));
});
}
@ -131,18 +131,20 @@ class SiteController extends Controller
public function update(UpdateSiteRequest $request, Site $site): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $site) {
/** @var array<int, array<string, mixed>> $logos */
$logos = $request->validated('logos') ?? [];
$site->logos()->sync(collect($logos)->pluck('id'));
$site->fill($request->safe()->except(['logos']));
$site->logos()->sync(collect($request->validated('logos'))->pluck('id'));
if ($site->saveOrFail()) {
return redirect()->route('bo.sites.edit', $site)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.site'))
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.site'))
]));
}
return redirect()->route('bo.sites.edit', $site)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.site'))
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.site'))
]));
});
}
@ -160,13 +162,13 @@ class SiteController extends Controller
if ($site->deleteOrFail()) {
return redirect()->route('bo.sites.index')
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.site'))
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.site'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.site'))
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.site'))
]));
});
}

View file

@ -28,17 +28,17 @@ class SlideController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $slideModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Slide> $slideModels */
$slideModels = Slide::query();
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$slideModels,
$search,
null,
'slider',
'type',
'title',
);
}
@ -81,13 +81,13 @@ class SlideController extends Controller
if ($slide->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.slides.edit', $slide)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.slide'))
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.slide'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.slide'))
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.slide'))
]));
});
}
@ -115,13 +115,13 @@ class SlideController extends Controller
return DB::transaction(function () use ($request, $slide) {
if ($slide->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.slides.edit', $slide)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.slide'))
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.slide'))
]));
}
return redirect()->route('bo.slides.edit', $slide)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.slide'))
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.slide'))
]));
});
}
@ -136,13 +136,13 @@ class SlideController extends Controller
{
if ($slide->deleteOrFail()) {
return redirect()->route('bo.slides.index')
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.slide'))
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.slide'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.slide'))
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.slide'))
]));
}

View file

@ -27,11 +27,11 @@ class StaticPageController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $query */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\StaticPage> $query */
$query = StaticPage::query();
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$query,
@ -78,12 +78,12 @@ class StaticPageController extends Controller
if ($static_page->saveOrFail()) {
return redirect()->route('bo.static_pages.edit', $static_page)
->with('success', __('crud.messages.has_been_updated', [
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(\trans_choice('models.classes.static_page', 1))
]));
}
return redirect()->route('bo.static_pages.edit', $static_page)
->with('error', __('crud.messages.cannot_be_updated', [
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(\trans_choice('models.classes.static_page', 1))
]));
});

View file

@ -0,0 +1,157 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Stickies\StoreStickyRequest;
use App\Http\Requests\Bo\Stickies\UpdateStickyRequest;
use App\Models\Sticky;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class StickyController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Sticky::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Sticky> $stickyModels */
$stickyModels = Sticky::query();
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$stickyModels,
$search,
null,
'title',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.title')),
]);
/** Sort columns with a query */
$this->sortQuery($stickyModels);
/** Custom pagination */
$stickyModels = $this->paginate($stickyModels);
return view('bo.pages.stickies.index', compact('stickyModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Sticky $sticky
* @return \Illuminate\Contracts\View\View
*/
public function create(Sticky $sticky): \Illuminate\Contracts\View\View
{
return view('bo.pages.stickies.create', ['stickyModel' => $sticky]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Stickies\StoreStickyRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreStickyRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$sticky = new Sticky();
if ($sticky->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.stickies.edit', $sticky)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans_choice('models.classes.sticky', 0))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans_choice('models.classes.sticky', 0))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Sticky $sticky
* @return \Illuminate\Contracts\View\View
*/
public function edit(Sticky $sticky): \Illuminate\Contracts\View\View
{
return view('bo.pages.stickies.edit', ['stickyModel' => $sticky]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Stickies\UpdateStickyRequest $request
* @param \App\Models\Sticky $sticky
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateStickyRequest $request, Sticky $sticky): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $sticky) {
if ($sticky->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.stickies.edit', $sticky)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.sticky', 0))
]));
}
return redirect()->route('bo.stickies.edit', $sticky)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.sticky', 0))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Sticky $sticky
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Sticky $sticky): \Illuminate\Http\RedirectResponse
{
if ($sticky->deleteOrFail()) {
return redirect()->route('bo.stickies.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.sticky', 0))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.sticky', 0))
]));
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Sticky $sticky
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Sticky $sticky): \Illuminate\Contracts\View\View
{
return $this->create($sticky->replicate());
}
}

View file

@ -9,6 +9,7 @@ use App\Models\News;
use App\Models\Strip;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
@ -32,11 +33,11 @@ class StripController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $stripModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Strip> $stripModels */
$stripModels = Strip::query()->with('news');
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$stripModels,
@ -46,7 +47,7 @@ class StripController extends Controller
);
}
$searchFields = \implode(', ', [
Str::ucfirst(__('validation.attributes.content')),
Str::ucfirst(trans('validation.attributes.content')),
]);
/** Sort columns with a query */
@ -91,12 +92,12 @@ class StripController extends Controller
if ($strip->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.strips.edit', $strip)
->with('success', __('crud.messages.has_been_created', [
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans_choice('models.classes.strip', 1))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans_choice('models.classes.strip', 1))
]));
});
@ -131,14 +132,23 @@ class StripController extends Controller
if ($request->news_id === null) {
$strip->news()->dissociate();
}
if (!Arr::exists($request->validated(), 'picture')) {
$strip->picture = null;
$strip->picture_alt = null;
$strip->picture_title = null;
} elseif (!Arr::exists($request->validated(), 'picto')) {
$strip->picto = null;
}
if ($strip->saveOrFail()) {
return redirect()->route('bo.strips.edit', $strip)
->with('success', __('crud.messages.has_been_updated', [
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.strip', 1))
]));
}
return redirect()->route('bo.strips.edit', $strip)
->with('error', __('crud.messages.cannot_be_updated', [
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.strip', 1))
]));
});
@ -154,12 +164,12 @@ class StripController extends Controller
{
if ($strip->deleteOrFail()) {
return redirect()->route('bo.strips.index')
->with('success', __('crud.messages.has_been_deleted', [
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.strip', 1))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.strip', 1))
]));
}

View file

@ -28,11 +28,11 @@ class TestimonialController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $testimonialModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Testimonial> $testimonialModels */
$testimonialModels = Testimonial::query();
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$testimonialModels,
@ -85,13 +85,13 @@ class TestimonialController extends Controller
if ($testimonial->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.testimonials.edit', $testimonial)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.testimonial'))
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.testimonial'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.testimonial'))
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.testimonial'))
]));
});
}
@ -121,13 +121,13 @@ class TestimonialController extends Controller
return DB::transaction(function () use ($request, $testimonial) {
if ($testimonial->fill($request->validated())->saveOrFail()) {
return redirect()->route('bo.testimonials.edit', $testimonial)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.testimonial'))
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.testimonial'))
]));
}
return redirect()->route('bo.testimonials.edit', $testimonial)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.testimonial'))
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.testimonial'))
]));
});
}
@ -142,13 +142,13 @@ class TestimonialController extends Controller
{
if ($testimonial->deleteOrFail()) {
return redirect()->route('bo.testimonials.index')
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.testimonial'))
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.testimonial'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.testimonial'))
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.testimonial'))
]));
}

View file

@ -5,7 +5,7 @@ namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\UploadFileRequest;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Section;
use Illuminate\Database\Eloquent\Model;
class UploadController extends Controller
{
@ -18,10 +18,19 @@ class UploadController extends Controller
*/
public function uploadFile(UploadFileRequest $request)
{
/** @var \Illuminate\Http\UploadedFile $image */
$image = $request->upload;
$modelClass = "App\\Models\\$request->folder";
$path = FileStorageHelper::storeFile(new Section(), $image, true);
if (!class_exists($modelClass) && !is_subclass_of($modelClass, Model::class)) {
return response()->json(['error' => 'Invalid model class'], 404);
}
/** @var \Illuminate\Database\Eloquent\Model $model */
$model = new $modelClass();
/** @var \Illuminate\Http\UploadedFile $image */
$image = $request->file('upload');
$path = FileStorageHelper::storeFile($model, $image, true);
return response()->json([
'url' => "/{$path}"

View file

@ -31,11 +31,11 @@ class UserController extends Controller
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $userModels */
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\User> $userModels */
$userModels = User::query();
/** @var string $search Search field */
$search = $request->search;
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$userModels,
@ -88,13 +88,13 @@ class UserController extends Controller
if ($user->saveOrFail()) {
return redirect()->route('bo.users.edit', $user)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.user'))
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.user'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.user'))
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.user'))
]));
});
}
@ -124,13 +124,13 @@ class UserController extends Controller
if ($user->saveOrFail()) {
return redirect()->route('bo.users.edit', $user)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.user'))
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.user'))
]));
}
return redirect()->route('bo.users.edit', $user)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.user'))
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.user'))
]));
});
}
@ -145,16 +145,16 @@ class UserController extends Controller
{
/** @var array<string,string> */
$previousQueries = [];
\parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries);
\parse_str((string) \parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries);
if ($user->deleteOrFail()) {
return redirect()->route('bo.users.index', $previousQueries)
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.user'))
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.user'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.user'))
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.user'))
]));
}

View file

@ -24,18 +24,19 @@ class Controller extends BaseController
* 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
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Database\Eloquent\Builder<TModel> $query The eloquent query builder.
* @param string $search The searched string.
* @param callable|null $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<TModel>
*/
protected function searchQuery(
Builder $query,
string $search,
callable $searchQuery = null,
callable|null $searchQuery = null,
string ...$fields
): \Illuminate\Database\Eloquent\Builder {
if (count($fields)) {
@ -61,15 +62,16 @@ class Controller extends BaseController
/**
* Build query search on all fields
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param array $fields
* @return \Illuminate\Database\Eloquent\Builder
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Database\Eloquent\Builder<TModel> $query
* @param string $search
* @param array<int|string, string|array<int, string>> $fields
* @return \Illuminate\Database\Eloquent\Builder<TModel>
*/
private function searchOnFields(
Builder $query,
string $search,
array $fields
array $fields,
): \Illuminate\Database\Eloquent\Builder {
$table = $query->getModel()->getTable();
foreach ($fields as $field) {
@ -115,13 +117,17 @@ class Controller extends BaseController
/**
* Get the search value (on string or Enum).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param string $field
* @return string|array
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Database\Eloquent\Builder<TModel> $query
* @param string $search
* @param string $field
* @return string|array<int, mixed>
*/
protected function getSearchValue(Builder $query, string $search, string $field): string|array
{
protected function getSearchValue(
Builder $query,
string $search,
string $field,
): string|array {
$cast = $query->getModel()->getCasts()[$field] ?? null;
if (
count($query->getModel()->getCasts()) and // Check if the model has casts.
@ -131,8 +137,8 @@ class Controller extends BaseController
/** @var \App\Traits\Enums $cast */
// @phpstan-ignore-next-line
$cases = collect($cast::toArray());
$enum = $cases->filter(function ($item) use ($search) {
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label));
$enum = $cases->filter(function ($item) use ($search): bool {
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label)) === 1;
});
return $enum->toArray();
} else {
@ -143,12 +149,15 @@ class Controller extends BaseController
/**
* Sort columns with a query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $ignore
* @return \Illuminate\Database\Eloquent\Builder
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Database\Eloquent\Builder<TModel> $query
* @param array<int, string> $ignore
* @return \Illuminate\Database\Eloquent\Builder<TModel>
*/
protected function sortQuery(Builder $query, array $ignore = []): \Illuminate\Database\Eloquent\Builder
{
protected function sortQuery(
Builder $query,
array $ignore = [],
): \Illuminate\Database\Eloquent\Builder {
$rName = request()->route()->getName();
$table = $query->getModel()->getTable();
if (request()->input('sort_col')) {
@ -194,13 +203,14 @@ class Controller extends BaseController
/**
* Customize pagination with cache or config (default).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Database\Eloquent\Builder<TModel> $query
* @param \App\Enums\Pagination\ItemsPerPaginationEnum|null $pagination
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<TModel>
*/
protected function paginate(
Builder $query,
ItemsPerPaginationEnum $pagination = null
ItemsPerPaginationEnum|null $pagination = null
): \Illuminate\Contracts\Pagination\LengthAwarePaginator {
$currentRoutePath = Str::slug(request()->route()->getName());
$cacheKey = "pagination.{$currentRoutePath}";
@ -208,7 +218,7 @@ class Controller extends BaseController
$pagination = ToolboxHelper::getValidatedEnum(
Cache::get($cacheKey, $pagination->value()),
'pagination',
'\App\Enums\Pagination\ItemsPerPaginationEnum',
ItemsPerPaginationEnum::class,
);
if (Cache::get($cacheKey) !== $pagination) {
Cache::put($cacheKey, $pagination);
@ -228,7 +238,7 @@ class Controller extends BaseController
$theme = ToolboxHelper::getValidatedEnum(
$request->theme ?: Cache::get('theme', BootstrapThemeEnum::light->value()),
'theme',
'\App\Http\Controllers\BootstrapThemeEnum',
BootstrapThemeEnum::class,
);
if (Cache::get("theme") !== $theme) {
Cache::put("theme", $theme);

View file

@ -1,29 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Enums\Testimonials\TypeEnum;
use App\Http\Controllers\Controller;
use App\Models\JobVideo;
use App\Models\Section;
use App\Models\StaticPage;
use App\Models\Testimonial;
class HireController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_hire)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$videoModels = JobVideo::query()->inRandomOrder()->simplePaginate(4);
$testimonialModels = Testimonial::query()->where('type', TypeEnum::hire)->get();
return view('fo.pages.hire', \compact('staticPageModel', 'sectionModels', 'videoModels', 'testimonialModels'));
}
}

View file

@ -1,53 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Enums\Sections\PageSectionEnum;
use App\Enums\Slides\SliderTypeEnum;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\News;
use App\Models\Section;
use App\Models\Slide;
use App\Models\StaticPage;
use App\Models\Strip;
class HomeController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::home)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$stripModels = Strip::query()->where('published', true)
->orderBy('publish_at', 'DESC')
->limit(6)
->with('news')
->get();
$newsModels = News::query()->where('published', true)
->orderBy('publish_at', 'DESC')
->limit(4)
->get();
$slideModels = Slide::query()->where('slider', SliderTypeEnum::home)->get();
$missionSection = $sectionModels->where('section', PageSectionEnum::home_missions)->first();
$ambitionSection = $sectionModels->where('section', PageSectionEnum::home_ambition)->first();
$teamSection = $sectionModels->where('section', PageSectionEnum::home_team)->first();
$lifeSection = $sectionModels->where('section', PageSectionEnum::home_life)->first();
return view('fo.pages.home', compact(
'staticPageModel',
'sectionModels',
'stripModels',
'newsModels',
'slideModels',
'missionSection',
'ambitionSection',
'teamSection',
'lifeSection',
));
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\Network;
class NetworkController extends Controller
{
/**
* Display the specified resource.
*
* @param \App\Models\Network $network
*
* @return \Illuminate\Contracts\View\View
*/
public function show(Network $network): \Illuminate\Contracts\View\View
{
$network->load(['aisles', 'aisles.brands']);
$networkModels = Network::query()
->whereNot('id', $network->id)
->where('published', true)
->orderBy('order')
->get();
return view('fo.pages.networks.show', [
'networkModel' => $network,
'networkModels' => $networkModels,
]);
}
}

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Fo;
use App\Enums\Sections\PageSectionEnum;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\News;
@ -17,35 +18,49 @@ class NewsController extends Controller
*/
public function index(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_move)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$newsModels = News::query()->where('published', true)->orderBy('order')->simplePaginate(4);
return view('fo.pages.news.index', \compact('staticPageModel', 'sectionModels', 'newsModels'));
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_move)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$newsModels = News::query()
->where('published', true)
->orderBy('displayed_date', 'DESC')
->simplePaginate(4)
->fragment('corpo');
$lifeSection = $sectionModels->where('section', PageSectionEnum::move_life)->first();
$commitmentSection = $sectionModels->where('section', PageSectionEnum::move_commitments)->first();
return view('fo.pages.news.index', \compact(
'staticPageModel',
'sectionModels',
'newsModels',
'lifeSection',
'commitmentSection'
));
}
/**
* Display a news articles
*
* @param string $slug
* @param \App\Models\News $news
* @return \Illuminate\Contracts\View\View
*/
public function show(News $news): \Illuminate\Contracts\View\View
{
/** @var \App\Models\News $nextNews */
if ($news->order === News::query()->where('published', true)->max('order')) {
$nextNews = News::query()
->where('published', true)
->orderBy('order')
->firstOrFail();
} else {
$nextNews = News::query()
->where('order', '>', $news->order)
->where('published', true)
->orderBy('order')
->firstOrFail();
}
// Get only id from published news.
$publishedNews = News::query()->where('published', true)->orderBy('publish_at', 'DESC')->get()->pluck('id');
// Search the position of the current news id.
$positionId = \array_search($news->id, $publishedNews->toArray());
// Check if it's the last position.
$nextPositionId = ($positionId === count($publishedNews) - 1) ? 0 : intval($positionId) + 1;
// Find the next news from the id.
$nextNews = News::query()->where('id', $publishedNews[$nextPositionId])->firstOrFail();
// Check if it's the first position.
$prevPositionId = ($positionId === 0) ? count($publishedNews) - 1 : intval($positionId) - 1;
// Find the next news from the id.
$prevNews = News::query()->where('id', $publishedNews[$prevPositionId])->firstOrFail();
return view('fo.pages.news.show', \compact('news', 'nextNews'));
return view('fo.pages.news.show', [
'news' => $news,
'nextNews' => $nextNews,
'prevNews' => $prevNews,
]);
}
}

View file

@ -1,29 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\Site;
class SiteController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \App\Models\Site $site
* @return \Illuminate\Contracts\View\View
*/
public function show(Site $site): \Illuminate\Contracts\View\View
{
if ($site->order === Site::query()->max('order')) {
$nextSiteModel = Site::query()->orderBy('order')->first();
} else {
$nextSiteModel = Site::query()->orderBy('order')->where('order', '>', $site->order)->first();
}
return view('fo.pages.site', [
'siteModel' => $site,
'nextSiteModel' => $nextSiteModel
]);
}
}

View file

@ -6,21 +6,74 @@ use App\Enums\Listen\ObjectEnum;
use App\Enums\Sections\PageSectionEnum;
use App\Enums\Slides\SliderTypeEnum;
use App\Enums\StaticPageType;
use App\Enums\StickiesColorEnum;
use App\Enums\Testimonials\TypeEnum;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\ListenFormRequest;
use App\Mail\SendConfirmationMail;
use App\Mail\SendContactMail;
use App\Models\Carousel;
use App\Models\HistoricalMilestone;
use App\Models\JobVideo;
use App\Models\Network;
use App\Models\News;
use App\Models\Section;
use App\Models\Site;
use App\Models\Slide;
use App\Models\StaticPage;
use App\Models\Sticky;
use App\Models\Strip;
use App\Models\Testimonial;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
class StaticPageController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Contracts\View\View
*/
public function show(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::home)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$stripModels = Strip::query()
->where('published', true)
->orderBy('publish_at', 'DESC')
->limit(6)
->with('news')
->whereHas('news', function (Builder $query) {
$query->where('published', true);
})
->get();
$newsModels = News::query()
->where('published', true)
->orderBy('displayed_date', 'DESC')
->limit(4)
->get();
$slideModels = Slide::query()->where('type', SliderTypeEnum::home)->get();
$missionSection = $sectionModels->where('section', PageSectionEnum::home_missions)->first();
$ambitionSection = $sectionModels->where('section', PageSectionEnum::home_ambition)->first();
$teamSection = $sectionModels->where('section', PageSectionEnum::home_team)->first();
$lifeSection = $sectionModels->where('section', PageSectionEnum::home_life)->first();
$slideTeams = Slide::query()->where('type', SliderTypeEnum::team)->get();
return view('fo.pages.home', compact(
'staticPageModel',
'sectionModels',
'stripModels',
'newsModels',
'slideModels',
'missionSection',
'ambitionSection',
'teamSection',
'lifeSection',
'slideTeams',
));
}
/**
* Display the 'unveil' page.
*
@ -29,17 +82,46 @@ class StaticPageController extends Controller
public function unveil(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::unveil)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$historicalMilestoneModels = HistoricalMilestone::query()
->orderBy('year', 'ASC')
->get();
$siteModel = Site::query()->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->getKey())->get();
$historicalMilestoneModels = HistoricalMilestone::query()->orderBy('year', 'ASC')->get();
/** @var \Illuminate\Database\Eloquent\Collection<array-key,\App\Models\Site> */
$siteModelList = Site::query()->orderBy('order')->get();
$keySection = $sectionModels->where('section', PageSectionEnum::unveil_pole)->first();
$missionsSection = $sectionModels->where('section', PageSectionEnum::unveil_missions)->first();
$localSection = $sectionModels->where('section', PageSectionEnum::unveil_local)->first();
$siteSection = $sectionModels->where('section', PageSectionEnum::unveil_sites)->first();
$historySection = $sectionModels->where('section', PageSectionEnum::unveil_history)->first();
$commitmentSection = $sectionModels->where('section', PageSectionEnum::unveil_commitments)->first();
$navLinks = Sticky::query()->where('type', StaticPageType::unveil)->get();
$viewBox = null;
$initialZoom = null;
// * Calcul Viewbox leaflet map ().
// Carte page “on se dévoile” : Point central = Laval + rayon = 100 km
/** @var \App\Models\Site|null $lavalSite */
$lavalSite = $siteModelList->first(fn(Site $site) => Str::contains($site->name, 'Laval'));
if ($lavalSite) {
$viewBox = (object) [
'lat' => $lavalSite->latitude,
'lng' => $lavalSite->longitude
];
$initialZoom = 9;
}
return view('fo.pages.unveil', compact(
'viewBox',
'initialZoom',
'staticPageModel',
'sectionModels',
'historicalMilestoneModels',
'siteModel'
'siteModelList',
'keySection',
'missionsSection',
'localSection',
'siteSection',
'historySection',
'commitmentSection',
'navLinks'
));
}
@ -50,12 +132,11 @@ class StaticPageController extends Controller
*/
public function commit(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_commit)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$slideModels = Slide::query()
->whereIn('slider', [SliderTypeEnum::better_life->value, SliderTypeEnum::respect_earth->value])
->get();
$testimonialModels = Testimonial::query()
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_commit)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$slideLifeModels = Slide::query()->where('type', SliderTypeEnum::better_life)->latest()->get();
$slideEarthModels = Slide::query()->where('type', SliderTypeEnum::respect_earth)->latest()->get();
$testimonialModels = Testimonial::query()
->whereIn('type', [
TypeEnum::breeding->value,
TypeEnum::better_life->value,
@ -63,8 +144,6 @@ class StaticPageController extends Controller
TypeEnum::feed->value,
TypeEnum::volena->value,
])->get();
/** Get all sections */
$ambitionSection = $sectionModels->where('section', PageSectionEnum::commit_ambition)->first();
$breedingSection = $sectionModels->where('section', PageSectionEnum::commit_breeding)->first();
$lifeSection = $sectionModels->where('section', PageSectionEnum::commit_living)->first();
@ -72,10 +151,13 @@ class StaticPageController extends Controller
$feedSection = $sectionModels->where('section', PageSectionEnum::commit_feed)->first();
$testimonialsSection = $sectionModels->where('section', PageSectionEnum::commit_commitments)->first();
$navLinks = Sticky::query()->where('type', StaticPageType::we_commit)->get();
return view('fo.pages.commitments', compact(
'staticPageModel',
'sectionModels',
'slideModels',
'slideLifeModels',
'slideEarthModels',
'testimonialModels',
'ambitionSection',
'breedingSection',
@ -83,6 +165,7 @@ class StaticPageController extends Controller
'earthSection',
'feedSection',
'testimonialsSection',
'navLinks',
));
}
@ -109,22 +192,57 @@ class StaticPageController extends Controller
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::confidentiality)->first();
return view('fo.pages.confidentiality', compact(
return view('fo.pages.legals', compact(
'staticPageModel',
));
}
/**
* Display the 'we_produce' page.
*
* @return \Illuminate\Contracts\View\View
*/
public function produce(): \Illuminate\Contracts\View\View
{
// MODELS.
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_produce)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$networkModels = Network::query()->where('published', true)->orderBy('order')->get();
// SECTIONS.
$localSection = $sectionModels->where('section', PageSectionEnum::produce_local)->first();
$gmsSection = $sectionModels->where('section', PageSectionEnum::produce_gms)->first();
$rhdSection = $sectionModels->where('section', PageSectionEnum::produce_rhd)->first();
$exportSection = $sectionModels->where('section', PageSectionEnum::produce_export)->first();
$qualitySection = $sectionModels->where('section', PageSectionEnum::produce_quality)->first();
$networkSection = $sectionModels->where('section', PageSectionEnum::produce_networks)->first();
return view('fo.pages.produce.show', compact(
'staticPageModel',
'networkModels',
'localSection',
'gmsSection',
'rhdSection',
'exportSection',
'qualitySection',
'networkSection',
));
}
/**
* Display the 'we_listen' page.
* This page is used to send a contact form.
*
* @return \Illuminate\Contracts\View\View
*/
public function listen(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_listen)->first();
$sectionModel = Section::query()->where('page_id', $staticPageModel->id)->first();
return view('fo.pages.listen', compact(
'staticPageModel',
'sectionModel',
));
}
@ -137,13 +255,97 @@ class StaticPageController extends Controller
public function listenForm(ListenFormRequest $request): \Illuminate\Http\RedirectResponse
{
Mail::to(config('mail.contact.' . ObjectEnum::make(intval($request->validated()['object']))->name()))
->send(new SendContactMail((object)$request->validated()));
Mail::to($request->validated()['email'])->send(new SendConfirmationMail((object)$request->validated()));
->send(new SendContactMail((object) $request->validated()));
Mail::to($request->validated()['email'])->send(new SendConfirmationMail((object) $request->validated()));
return redirect()->route('fo.listen')
return redirect()->route('fo.listen.show')
->with('success', trans(
'Bonjour, votre message a bien été transmis, nous vous en remercions. Cordialement, l’équipe :appName.',
['appName' => config('app.name')]
));
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Contracts\View\View
*/
public function hire(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_hire)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$videoModels = JobVideo::query()->inRandomOrder()->simplePaginate(4);
$testimonialModels = Testimonial::query()->where('type', TypeEnum::hire)->get();
$compagnyLifeSection = $sectionModels->where('section', PageSectionEnum::hire_life)->first();
$formationSection = $sectionModels->where('section', PageSectionEnum::hire_formation)->first();
$testimonialSection = $sectionModels->where('section', PageSectionEnum::hire_grow)->first();
$paritySection = $sectionModels->where('section', PageSectionEnum::hire_parity)->first();
$findSection = $sectionModels->where('section', PageSectionEnum::hire_find)->first();
$carouselSectionParity = Carousel::query()
->where('section_id', PageSectionEnum::hire_parity)
->where('published', true)
->orderBy('order')
->get();
$navLinks = Sticky::query()->where('type', StaticPageType::we_hire)->get();
return view('fo.pages.hire', \compact(
'staticPageModel',
'sectionModels',
'videoModels',
'testimonialModels',
'compagnyLifeSection',
'formationSection',
'testimonialSection',
'paritySection',
'findSection',
'carouselSectionParity',
'navLinks'
));
}
/**
* Display a listing of the resource.
*
* @param \App\Models\Site $site
* @return \Illuminate\Contracts\View\View
*/
public function site(Site $site): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Collection<array-key,\App\Models\Site> */
$siteModels = Site::query()->orderBy('order')->get();
$siteModelList = $siteModels->keyBy('order');
$nextSiteModel = $siteModelList->where(
'order',
'>',
$site->order
)->first();
if ($siteModelList->last()->is($site)) {
$nextSiteModel = $siteModelList->first();
}
$viewBox = (object) [
'lat' => $site->latitude,
'lng' => $site->longitude
];
$initialZoom = 10;
// Create datas similar to Sticky model.
$navLinks = collect([
(object) [
'title' => $site->sticky_title,
'anchor' => $site->sticky_link,
'color' => StickiesColorEnum::quad,
],
]);
return view('fo.pages.site', [
'siteModelList' => $siteModelList,
'siteModel' => $site,
'nextSiteModel' => $nextSiteModel,
'viewBox' => $viewBox,
'initialZoom' => $initialZoom,
'navLinks' => $navLinks,
]);
}
}

View file

@ -39,7 +39,11 @@ class Kernel extends HttpKernel
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\SecureHeaders::class
],
'saml' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
],
'api' => [
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,

View file

@ -4,7 +4,6 @@ namespace App\Http\Middleware;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class HtmlSanitizer
{
@ -13,11 +12,14 @@ class HtmlSanitizer
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|array ...$params
* @param string|array<int, mixed> ...$params
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle(Request $request, \Closure $next, string|array ...$params): Response
{
public function handle(
Request $request,
\Closure $next,
string|array ...$params
): \Symfony\Component\HttpFoundation\Response {
$inputs = $request->all();
/** @var callable|null */
$cleanInput = null;

View file

@ -3,7 +3,6 @@
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class RedirectIfAuthenticated
{
@ -17,7 +16,7 @@ class RedirectIfAuthenticated
* @throws \RuntimeException If guard is unhandled.
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
*/
public function handle(Request $request, \Closure $next, ...$guards): Response
public function handle(Request $request, \Closure $next, ...$guards): \Symfony\Component\HttpFoundation\Response
{
// phpcs:enable phpcs:disable
$guards = empty($guards) ? [null] : $guards;
@ -26,10 +25,10 @@ class RedirectIfAuthenticated
if (auth($guard)->check()) {
switch ($guard) {
case 'frontend':
return \redirect()->route('fo.homepage');
return \redirect()->route('fo.home.show');
case 'backend':
if (!$request->routeIs('bo.*')) {
continue;
continue 2;
}
return \redirect()->route('bo.dashboard');
default:

View file

@ -7,7 +7,6 @@ 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
{
@ -16,7 +15,7 @@ class SecureHeaders
* Great starting point would be to go check out @Scott_Helme's:
* https://securityheaders.com/
*
* @var array
* @var list<string>
*/
private $unwantedHeaderList = [
'X-Powered-By',
@ -31,7 +30,7 @@ class SecureHeaders
* @return \Symfony\Component\HttpFoundation\Response
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
*/
public function handle(Request $request, Closure $next): Response
public function handle(Request $request, Closure $next): \Symfony\Component\HttpFoundation\Response
{
// phpcs:enable
// * For Vite DEV
@ -60,6 +59,10 @@ class SecureHeaders
'https://yl.s-web.fr'
]) . ';',
"img-src 'self' data: blob: " . implode(' ', [
// * Leaftlet With OpenStreetmaps
'https://tile.openstreetmap.org',
// * Youtube thumbnails
'https://img.youtube.com/vi/',
// * VITE DEV
config('app.debug') ? "https://{$host}:4443" : '',
]) . ';',
@ -67,7 +70,8 @@ class SecureHeaders
"frame-src 'self' " . implode(' ', [
'https://www.google.com/recaptcha/',
'https://recaptcha.google.com/recaptcha/',
'https://www.google.com/maps/'
'https://www.youtube.com',
'https://www.youtube-nocookie.com/embed/',
]) . ';',
"font-src 'self' data: " . \implode(' ', [
// * VITE DEV
@ -108,9 +112,9 @@ class SecureHeaders
}
/**
* Remove unwanted headers
* Remove unwanted headers.
*
* @param array $headerList
* @param list<string> $headerList
* @return void
*/
private function removeUnwantedHeaders(array $headerList): void

View file

@ -11,7 +11,7 @@ class TrustHosts extends Middleware
*
* @return array<int, string|null>
*/
public function hosts()
public function hosts(): array
{
return [
$this->allSubdomainsOfApplicationUrl(),

View file

@ -0,0 +1,61 @@
<?php
namespace App\Http\Requests\Bo\Aisles;
use App\Rules\WysiwygLength;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
class StoreAisleRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
]);
$this->mergePicture('picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'name' => 'required|string|between:3,255',
'title' => 'required|string|between:3,255',
'text' => [
'required',
'string',
new WysiwygLength(3, 500),
],
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
'network_id' => 'required|exists:networks,id',
'published' => 'required|boolean',
];
return \array_merge(
$rules,
$this->pictureRules('picture', 1400, 450, 1400, 450, false),
);
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\Aisles;
class UpdateAisleRequest extends StoreAisleRequest
{
}

View file

@ -0,0 +1,61 @@
<?php
namespace App\Http\Requests\Bo\Brands;
use App\Rules\WysiwygLength;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
class StoreBrandRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
]);
$this->mergePicture('picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'name' => 'required|string|between:3,255',
'text' => [
'required',
'string',
new WysiwygLength(3, 500),
],
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
'link' => 'nullable|url:https',
'aisle_id' => 'required|exists:aisles,id',
'published' => 'required|boolean',
];
return \array_merge(
$rules,
$this->pictureRules('picture', 250, 250, 250, 250, false),
);
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\Brands;
class UpdateBrandRequest extends StoreBrandRequest
{
}

View file

@ -0,0 +1,127 @@
<?php
namespace App\Http\Requests\Bo\Carousels;
use App\Models\Section;
use App\Rules\IsMaxChildrenReached;
use App\Rules\WysiwygLength;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Arr;
use Illuminate\Validation\Rule;
class StoreCarouselRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
if ($this->input('media.pictures')) {
foreach ($this->input('media.pictures') as $index => $pictureArray) {
$this->mergePicture("media.pictures.$index.path");
}
}
$this->merge([
'published' => $this->boolean('published'),
]);
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'title' => 'required|string|between:3,255',
'section_id' => [
'required',
Rule::exists('sections', 'id'),
new IsMaxChildrenReached(new Section(), 'carousels', 5)
],
'media' => 'required|array',
'media.pictures.*.alt' => 'sometimes|string|between:3,255',
'media.pictures.*.title' => 'sometimes|string|between:3,255',
'media.pictures.*.legend' => [
'sometimes',
'string',
new WysiwygLength(3, 255),
],
'published' => 'required|boolean',
];
if ($this->input('media')) {
if (Arr::exists($this->input('media'), 'pictures')) {
foreach ($this->input('media')['pictures'] as $pictureIndex => $pictureArray) {
$rules = array_merge(
$rules,
[
"media.pictures.$pictureIndex.alt" => 'required|string|between:3,255',
"media.pictures.$pictureIndex.title" => 'required|string|between:3,255',
"media.pictures.$pictureIndex.legend" => [
'sometimes',
'string',
new WysiwygLength(3, 255),
],
],
$this->pictureRules("media.pictures.$pictureIndex.path", 500, 500, 500, 500, false),
);
}
} //end if
} //end if
return $rules;
}
/**
* Get custom attributes for validator errors.
*
* @return array<string, string>
*/
public function attributes(): array
{
$attributes = [
'title' => trans('validation.attributes.title'),
];
if ($this->input('media') && array_key_exists('pictures', $this->input('media'))) {
foreach ($this->input('media.pictures') as $index => $pictureArray) {
$attributes = array_merge(
$attributes,
[
"media.pictures.$index.alt" => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => sprintf('%s n°%d', trans('validation.custom.picture'), $index + 1),
]),
"media.pictures.$index.title" => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => sprintf('%s n°%d', trans('validation.custom.picture'), $index + 1),
]),
"media.pictures.$index.legend" => trans(':field :inter:model', [
'field' => trans('validation.custom.legend'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => sprintf('%s n°%d', trans('validation.custom.picture'), $index + 1),
]),
],
);
} //end foreach
} //end if
return $attributes;
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\Carousels;
class UpdateCarouselRequest extends StoreCarouselRequest
{
}

View file

@ -24,7 +24,7 @@ class StoreHistoricalMilestoneRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'button_status' => $this->boolean('button_status'),
@ -36,7 +36,7 @@ class StoreHistoricalMilestoneRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -61,7 +61,7 @@ class StoreHistoricalMilestoneRequest extends FormRequest
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
@ -69,15 +69,15 @@ class StoreHistoricalMilestoneRequest extends FormRequest
'year' => trans('validation.attributes.year'),
'title' => trans('validation.attributes.title'),
'text' => trans('validation.custom.text'),
'picture_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture'),
'picture_alt' => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture'),
]),
'picture_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture'),
'picture_title' => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture'),
]),
'button_label' => trans('validation.custom.button_label'),
'button_url' => trans('validation.custom.button_url'),

View file

@ -22,7 +22,7 @@ class StoreJobVideoRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -36,13 +36,13 @@ class StoreJobVideoRequest extends FormRequest
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
return [
'title' => trans('validation.attributes.title'),
'place' => trans('validation.custom.place'),
'title' => trans('validation.attributes.title'),
'place' => trans('validation.custom.place'),
'video_id' => trans('validation.custom.video_id'),
];
}

View file

@ -24,7 +24,7 @@ class StoreLogoRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->mergePicture('picture');
}
@ -32,7 +32,7 @@ class StoreLogoRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -44,27 +44,27 @@ class StoreLogoRequest extends FormRequest
];
return \array_merge(
$rules,
$this->pictureRules('picture', 331, 240, 331, 100, false),
$this->pictureRules('picture', 450, 450, 450, 450, false),
);
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
return [
'picture_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture'),
'picture_alt' => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture'),
]),
'picture_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture'),
'picture_title' => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture'),
]),
];
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Http\Requests\Bo\Networks;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
class StoreNetworkRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
]);
$this->mergePicture('picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'seo_title' => 'required|string|between:45,70',
'seo_description' => 'required|string|between:50,160',
'name' => 'required|string|between:3,255',
'title' => 'required|string|between:3,255',
'subtitle' => 'required|string|between:3,255',
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
'button_text' => 'required|string|between:3,255',
'published' => 'required|boolean',
];
return \array_merge(
$rules,
$this->pictureRules('picture', 1920, 1080, 1920, 1080, false),
);
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\Networks;
class UpdateNetworkRequest extends StoreNetworkRequest
{
}

View file

@ -24,7 +24,7 @@ class StoreNewsRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
@ -36,7 +36,7 @@ class StoreNewsRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -53,21 +53,21 @@ class StoreNewsRequest extends FormRequest
'linkedin_url' => 'nullable|url',
'published' => 'required|boolean',
'publish_at' => 'nullable|date',
'displayed_date' => 'required|date',
'unpublish_at' => 'nullable|date|after:publish_at',
];
return \array_merge(
$rules,
// FIXME: Mettre à jour les tailles.
$this->pictureRules('picture', 100, 100, 100, 100, false),
$this->pictureRules('thumbnail', 100, 100, 100, 100, false),
$this->pictureRules('picture', 500, 390, 500, 390, true),
$this->pictureRules('thumbnail', 660, 440, 660, 440, true),
);
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
@ -85,6 +85,7 @@ class StoreNewsRequest extends FormRequest
'published' => trans('validation.custom.activated'),
'publish_at' => trans('validation.custom.publish_at'),
'unpublish_at' => trans('validation.custom.unpublish_at'),
'displayed_date' => trans('validation.custom.displayed_date'),
];
}
}

View file

@ -36,7 +36,9 @@ class UpdateSectionRequest extends UpdateMiniCrudRequest
/** @var \App\Models\Section|null $section */
$section = $this->route('section');
if ($section) {
if ($section->section !== \App\Enums\Sections\PageSectionEnum::hire_grow) {
if (
$section->section !== \App\Enums\Sections\PageSectionEnum::hire_grow
) {
$rules = \array_merge($rules, [
'text' => 'present',
]);
@ -48,25 +50,20 @@ class UpdateSectionRequest extends UpdateMiniCrudRequest
]);
}
}
return \array_merge(
parent::rules(),
$rules
);
return \array_merge(parent::rules(), $rules);
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes()
public function attributes(): array
{
return [
'h2_title' => __('validation.custom.h2_title'),
'text' => __('validation.attributes.content'),
'data' => trans('Valeurs du contenu spécifique'),
'h2_title' => trans('validation.custom.h2_title'),
'text' => trans('validation.attributes.content'),
'data' => trans('Valeurs du contenu spécifique'),
'data.*.value' => trans('Valeur du contenu spécifique'),
];
}

View file

@ -25,152 +25,146 @@ class StoreSiteRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
/** @var array<int, mixed> $pictos */
$pictos = $this->input('pictos') ?? [];
$this->merge([
'published' => $this->boolean('published'),
'pictos' => \collect($this->input('pictos'))->all(),
'published' => $this->boolean('published'),
'invert_director_block' => $this->boolean('invert_director_block'),
'pictos' => \collect($pictos)->all(),
]);
$this->mergePicture('logo');
$this->mergePicture('picture_1');
$this->mergePicture('picture_2');
$this->mergePicture('picture_3');
$this->mergePicture('map_picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'seo_title' => 'required|between:45,70',
'seo_description' => 'required|between:50,160',
'name' => 'required|string|between:3,100',
'description' => 'required|string|between:3,255',
'description_2' => 'nullable|string|between:3,255',
'employees' => 'required|numeric|min:0',
'pictos' => 'present|array',
'pictos.*' => 'required|integer',
'address' => 'required|string|between:3,255',
'phone_number' => 'required|string|between:10,20',
'access_line' => 'present|array',
'access_line.*' => 'nullable|string|between:3,255',
'director_name' => 'nullable|string|between:3,255',
'director_speach' => 'required|string|min:15',
'employee_name' => 'nullable|string|between:3,255',
'employee_function' => 'nullable|string|between:3,255',
'employee_speach' => 'nullable|string|min:15',
'highlights' => 'nullable|string|min:15',
'latitude' => 'required|numeric|between:-90,90',
'longitude' => 'required|numeric|between:-180,180',
'logo_alt' => 'required|string|between:3,255',
'logo_title' => 'required|string|between:3,255',
'picture_1_alt' => 'required|string|between:3,255',
'picture_1_title' => 'required|string|between:3,255',
'picture_2_alt' => 'required_with:picture_2|nullable|string|between:3,255',
'picture_2_title' => 'required_with:picture_2|nullable|string|between:3,255',
'picture_3_alt' => 'required_with:picture_3|nullable|string|between:3,255',
'picture_3_title' => 'required_with:picture_3|nullable|string|between:3,255',
'map_picture_alt' => 'required|string|between:3,255',
'map_picture_title' => 'required|string|between:3,255',
'logos' => 'nullable|array',
'logos.*.id' => 'required|exists:logos,id',
'seo_title' => 'required|between:45,70',
'seo_description' => 'required|between:50,160',
'name' => 'required|string|between:3,100',
'description' => 'required|string|between:3,255',
'description_2' => 'nullable|string|between:3,255',
'employees' => 'required|numeric|min:0',
'pictos' => 'present|array',
'pictos.*' => 'required|integer',
'address' => 'required|string|between:3,255',
'phone_number' => 'required|string|between:10,20',
'access_line' => 'present|array',
'access_line.*' => 'nullable|string|between:3,255',
'director_name' => 'required|string|between:3,255',
'director_function' => 'required|string|between:3,255',
'director_speach' => 'required|string|min:15',
'invert_director_block' => 'required|boolean',
'employee_name' => 'nullable|string|between:3,255',
'employee_function' => 'nullable|string|between:3,255',
'employee_speach' => 'nullable|string|min:15',
'highlights' => 'nullable|string|min:15',
'latitude' => 'required|numeric|between:-90,90',
'longitude' => 'required|numeric|between:-180,180',
'sticky_title' => 'required_with:sticky_link|nullable|string|between:3,255',
'sticky_link' => 'required_with:sticky_title|nullable|string|between:3,255',
'logo_alt' => 'required|string|between:3,255',
'logo_title' => 'required|string|between:3,255',
'picture_1_alt' => 'required|string|between:3,255',
'picture_1_title' => 'required|string|between:3,255',
'picture_2_alt' => 'required_with:picture_2|nullable|string|between:3,255',
'picture_2_title' => 'required_with:picture_2|nullable|string|between:3,255',
'picture_3_alt' => 'required_with:picture_3|nullable|string|between:3,255',
'picture_3_title' => 'required_with:picture_3|nullable|string|between:3,255',
'logos' => 'nullable|array',
'logos.*.id' => 'required|exists:logos,id',
];
return \array_merge(
$rules,
// FIXME: Mettre à jour les tailles.
$this->pictureRules('logo', 100, 100, 100, 100, false),
$this->pictureRules('picture_1', 100, 100, 100, 100, false),
$this->pictureRules('picture_2', 100, 100, 100, 100, true),
$this->pictureRules('picture_3', 100, 100, 100, 100, true),
$this->pictureRules('map_picture', 100, 100, 100, 100, false),
$this->pictureRules('logo', 1000, 727, 1000, 727, false),
$this->pictureRules('picture_1', 1000, 562, 1000, 562, false),
$this->pictureRules('picture_2', 1000, 562, 1000, 562, true),
$this->pictureRules('picture_3', 1000, 562, 1000, 562, true),
);
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
return [
'seo_title' => __('validation.custom.seo_title'),
'seo_description' => __('validation.custom.seo_description'),
'name' => __('validation.attributes.name'),
'description' => __('validation.custom.description'),
'description_2' => __('validation.custom.description_2'),
'employees' => __('validation.custom.employees_count'),
'pictos' => Str::plural(__('validation.custom.picto')),
'pictos.*' => __('validation.custom.picto'),
'address' => __('validation.attributes.address'),
'phone_number' => __('validation.attributes.phone'),
'access_line' => __('validation.custom.access_line'),
'access_line.*' => __('ligne d\'accès au site'),
'director_name' => __('validation.custom.director_name'),
'director_speach' => __('validation.custom.director_speach'),
'employee_name' => __('validation.custom.employee_name'),
'employee_function' => __('validation.custom.employee_function'),
'employee_speach' => __('validation.custom.employee_speach'),
'highlights' => Str::plural(__('validation.custom.highlight')),
'latitude' => __('validation.custom.latitude'),
'longitude' => __('validation.custom.longitude'),
'logos' => Str::plural(__('models.classes.logo')),
'logos.*' => __('models.classes.logo'),
'logo_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.male'),
'model' => __('validation.custom.logo'),
'seo_title' => trans('validation.custom.seo_title'),
'seo_description' => trans('validation.custom.seo_description'),
'name' => trans('validation.attributes.name'),
'description' => trans('validation.custom.description'),
'description_2' => trans('validation.custom.description_2'),
'employees' => trans('validation.custom.employees_count'),
'pictos' => Str::plural(trans('validation.custom.picto')),
'pictos.*' => trans('validation.custom.picto'),
'address' => trans('validation.attributes.address'),
'phone_number' => trans('validation.attributes.phone'),
'access_line' => trans('validation.custom.access_line'),
'access_line.*' => trans('ligne d\'accès au site'),
'director_name' => trans('validation.custom.director_name'),
'director_function' => trans('validation.custom.director_function'),
'director_speach' => trans('validation.custom.director_speach'),
'invert_director_block' => trans('validation.custom.invert_block'),
'employee_name' => trans('validation.custom.employee_name'),
'employee_function' => trans('validation.custom.employee_function'),
'employee_speach' => trans('validation.custom.employee_speach'),
'highlights' => Str::plural(trans('validation.custom.highlight')),
'latitude' => trans('validation.custom.latitude'),
'longitude' => trans('validation.custom.longitude'),
'sticky_title' => trans('validation.custom.sticky_item.title'),
'sticky_link' => trans('validation.custom.sticky_item.link'),
'logos' => Str::plural(trans('models.classes.logo')),
'logos.*' => trans('models.classes.logo'),
'logo_alt' => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.male'),
'model' => trans('validation.custom.logo'),
]),
'logo_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.male'),
'model' => __('validation.custom.logo'),
'logo_title' => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.male'),
'model' => trans('validation.custom.logo'),
]),
'picture_1_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture_1'),
'picture_1_alt' => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture_1'),
]),
'picture_1_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture_1'),
'picture_1_title' => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture_1'),
]),
'picture_2_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture_2'),
'picture_2_alt' => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture_2'),
]),
'picture_2_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture_2'),
'picture_2_title' => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture_2'),
]),
'picture_3_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture_3'),
'picture_3_alt' => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture_3'),
]),
'picture_3_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture_3'),
]),
'map_picture_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.map_picture'),
]),
'map_picture_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.map_picture'),
'picture_3_title' => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture_3'),
]),
];
}

View file

@ -2,6 +2,8 @@
namespace App\Http\Requests\Bo\Slides;
use App\Enums\Slides\SliderTypeEnum;
use App\Rules\WysiwygLength;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
@ -25,78 +27,114 @@ class StoreSlideRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'button_status' => $this->boolean('button_status'),
'button_new_tab' => $this->boolean('button_new_tab')
'button_new_tab' => $this->boolean('button_new_tab'),
]);
if (intval($this->slider) !== \App\Enums\Slides\SliderTypeEnum::home->value()) {
$this->merge([
'video_id' => ''
]);
};
$this->mergePicture('picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'slider' => [
'type' => [
'required',
new Enum(\App\Enums\Slides\SliderTypeEnum::class)
new Enum(SliderTypeEnum::class)
],
'title' => [
'required_unless:slider,' . \App\Enums\Slides\SliderTypeEnum::home->value(),
'required_unless:type,' . SliderTypeEnum::home->value(),
'nullable',
'string',
'between:3,255'
],
'content' => 'required|string|between:3,255',
'content' => [
'required_if:type,' . SliderTypeEnum::home->value() . ', ' . SliderTypeEnum::team->value(),
'nullable',
'string',
new WysiwygLength(3, 275),
'max:500'
],
'video_id' => 'nullable|string|regex:%([^"&?\/\s]{11})%i',
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
'picture_alt' => [
'required_unless:type,' . SliderTypeEnum::team->value(),
'nullable',
'string',
'between:3,255'
],
'picture_title' => [
'required_unless:type,' . SliderTypeEnum::team->value(),
'nullable',
'string',
'between:3,255'
],
'button_label' => 'required_if:button_status,true|nullable|string|between:3,35',
'button_url' => 'required_if:button_status,true|nullable|string|between:3,255',
'button_status' => 'required|boolean',
'button_status' => [
'required_unless:type,' . SliderTypeEnum::home->value() . ', ' . SliderTypeEnum::team->value(),
'nullable',
'boolean'
],
'button_new_tab' => 'required|boolean',
];
return \array_merge(
$rules,
// FIXME: Mettre à jour les tailles.
$this->pictureRules('picture', 2030, 765, 2030, 765, false),
$this->pictureRules('picture', 1920, 1080, 1920, 1080, true)
);
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
return [
'video_id' => trans('validation.custom.video_id'),
'type' => trans('validation.custom.type'),
'title' => trans('validation.attributes.title'),
'content' => trans('validation.attributes.content'),
'video_id' => trans('validation.custom.video_id'),
'picture' => trans('validation.custom.picture'),
'picture_alt' => trans('validation.custom.picture_alt'),
'picture_title' => trans('validation.custom.picture_title'),
'button_label' => trans('validation.custom.button_label'),
'button_url' => trans('validation.custom.button_url'),
'button_status' => trans('validation.custom.button_status'),
'button_new_tab' => trans('validation.custom.button_new_tab'),
];
}
/**
* Custom validaton messages.
*
* @return array
* @return array<string, string>
*/
public function messages()
public function messages(): array
{
return [
'title' => [
'required_unless' => __('Le champ titre est obligatoire si le slider n\'est pas home.'),
]
'title.required_unless' => __('Le champ :attribute est obligatoire si le slider n\'est pas :name.', [
'attribute' => trans('validation.attributes.title'),
'name' => SliderTypeEnum::home->label()
]),
'content.required_if' => __('Le champ :attribute est obligatoire si le slider est :name1 ou :name2.', [
'attribute' => trans('validation.attributes.content'),
'name1' => SliderTypeEnum::home->label(),
'name2' => SliderTypeEnum::team->label()
]),
'content.max' => __(
'Le champ :attribute ne peut pas contenir plus de :max caractères (balises incluses).',
[
'attribute' => trans('validation.attributes.content'),
'max' => '500',
]
),
];
}
}

View file

@ -2,12 +2,15 @@
namespace App\Http\Requests\Bo\StaticPages;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
class UpdateStaticPageRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
@ -26,8 +29,11 @@ class UpdateStaticPageRequest extends FormRequest
public function prepareForValidation(): void
{
$this->merge([
'content' => Str::of($this->input('content'))->value()
'content' => (empty(Str::of($this->input('content'))->value())) ?
null :
Str::of($this->input('content'))->value()
]);
$this->mergePicture('picture');
}
/**
@ -37,18 +43,32 @@ class UpdateStaticPageRequest extends FormRequest
*/
public function rules(): array
{
return [
$rules = [
'seo_title' => 'required|min:45|max:70',
'seo_description' => 'required|min:50|max:160',
'title' => 'required|min:3|max:255',
'content' => 'present',
'content' => 'sometimes|nullable',
];
if (request()->route()->parameters()['static_page']->type->containsContent()) {
$rules = array_merge($rules, ['content' => 'required|string|min:15']);
}
if (request()->route()->parameters()['static_page']->type->containsBanner()) {
$rules = array_merge(
$rules,
$this->pictureRules('picture', 1920, 1080, 1920, 1080, false),
[
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
]
);
}
return $rules;
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
@ -57,6 +77,9 @@ class UpdateStaticPageRequest extends FormRequest
'seo_description' => trans('validation.custom.seo_description'),
'title' => trans('validation.attributes.title'),
'content' => trans('validation.attributes.content'),
'picture' => trans('validation.custom.banner'),
'picture_alt' => trans('validation.custom.attribute_alt'),
'picture_title' => trans('validation.custom.attribute_title'),
];
}
}

View file

@ -0,0 +1,62 @@
<?php
namespace App\Http\Requests\Bo\Stickies;
use App\Enums\StaticPageType;
use App\Enums\StickiesColorEnum;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Enum;
class StoreStickyRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'type' => [
Rule::requiredIf($this->user()->can('create', $this->sticky)),
new Enum(StaticPageType::class)
],
'title' => 'required|string|between:3,255',
'anchor' => [
Rule::requiredIf($this->user()->can('create', $this->sticky)),
'string',
'between:3,255'
],
'color' => [
Rule::requiredIf($this->user()->can('create', $this->sticky)),
new Enum(StickiesColorEnum::class)
],
];
}
/**
* Get custom attributes for validator errors.
*
* @return array<string, string>
*/
public function attributes(): array
{
return [
'type' => trans('validation.custom.type'),
'title' => trans('validation.attributes.title'),
'anchor' => trans('validation.custom.anchor'),
'color' => trans('validation.custom.color'),
];
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\Stickies;
class UpdateStickyRequest extends StoreStickyRequest
{
}

View file

@ -2,9 +2,9 @@
namespace App\Http\Requests\Bo\Strips;
use App\Rules\WysiwygLength;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules\Enum;
class StoreStripRequest extends FormRequest
@ -26,60 +26,76 @@ class StoreStripRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published'),
]);
if ($this->input('picture')) {
$this->mergePicture('picture');
}
}
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'picto' => [
'required',
new Enum(\App\Enums\Strips\PictoEnum::class)
],
$rules = [
'text' => [
'required',
'string',
'min:3',
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
function (string $attribute, mixed $value, \Closure $fail) {
if (Str::wordCount(\strip_tags($value)) > 255) {
$fail(trans('validation.max_words', [
'attribute' => trans('validation.attributes.text'),
'count' => '255'
]));
}
}
new WysiwygLength(3, 90),
],
'news_id' => 'nullable|exists:news,id',
'published' => 'required|boolean',
'publish_at' => 'nullable|date',
'unpublish_at' => 'nullable|date|after:publish_at',
];
if ($this->input('picture')) {
$rules = array_merge(
$rules,
[
'picture_alt' => 'required_with|string|between:3,255',
'picture_title' => 'required_with|string|between:3,255',
],
$this->pictureRules('picture', 100, 65, 100, 65, true),
);
} else {
$rules = array_merge(
$rules,
[
'picto' => [
'required',
new Enum(\App\Enums\Strips\PictoEnum::class)
],
],
);
}
return $rules;
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
return [
'picto' => __('validation.custom.picto'),
'text' => __('validation.attributes.content'),
'news_id' => __('models.classes.news'),
'published' => __('validation.custom.activated'),
'publish_at' => __('validation.custom.publish_at'),
'unpublish_at' => __('validation.custom.unpublish_at'),
'picto' => trans('validation.custom.picto'),
'picture' => trans('validation.custom.picture'),
'picture_alt' => trans('validation.custom.alt_attribute'),
'picture_title' => trans('validation.custom.title_attribute'),
'text' => trans('validation.attributes.content'),
'news_id' => trans('models.classes.news'),
'published' => trans('validation.custom.activated'),
'publish_at' => trans('validation.custom.publish_at'),
'unpublish_at' => trans('validation.custom.unpublish_at'),
];
}
}

View file

@ -25,7 +25,7 @@ class StoreTestimonialRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->mergePicture('picture');
}
@ -33,7 +33,7 @@ class StoreTestimonialRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -50,32 +50,31 @@ class StoreTestimonialRequest extends FormRequest
];
return \array_merge(
$rules,
// FIXME: Mettre à jour les tailles.
$this->pictureRules('picture', 100, 100, 100, 100, false),
$this->pictureRules('picture', 150, 150, 150, 150, false),
);
}
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
return [
'type' => __('validation.custom.type'),
'name' => __('validation.attributes.name'),
'job' => __('validation.custom.job'),
'content' => __('validation.attributes.content'),
'picture_alt' => __(':field :inter:model', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture'),
'type' => trans('validation.custom.type'),
'name' => trans('validation.attributes.name'),
'job' => trans('validation.custom.job'),
'content' => trans('validation.attributes.content'),
'picture_alt' => trans(':field :inter:model', [
'field' => trans('validation.custom.alt_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture'),
]),
'picture_title' => __(':field :inter:model', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.vowel'),
'model' => __('validation.custom.picture'),
'picture_title' => trans(':field :inter:model', [
'field' => trans('validation.custom.title_attribute'),
'inter' => trans('validation.custom.of_the.vowel'),
'model' => trans('validation.custom.picture'),
]),
];
}

View file

@ -31,7 +31,7 @@ class UpdateChangeOrderRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{

View file

@ -10,7 +10,7 @@ use Illuminate\Validation\ValidationException;
abstract class UpdateMiniCrudRequest extends FormRequest
{
/**
* The model parameter name
* The model parameter name.
*
* @var string
*/
@ -29,8 +29,8 @@ abstract class UpdateMiniCrudRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
* @phpcs:disable Generic.Metrics.NestingLevel.TooHigh
*/
public function rules(): array
@ -38,7 +38,8 @@ abstract class UpdateMiniCrudRequest extends FormRequest
// phpcs:enable
$rules = [];
foreach ($this->{$this->modelName}->data as $iptName => $input) {
$input = \json_decode(\json_encode($input), true);
$encoded = \json_encode($input);
$input = \json_decode($encoded !== false ? $encoded : '[]', true);
switch ($input['inputType']) {
case InputType::number->value:
$rules = array_merge($rules, [
@ -71,7 +72,7 @@ abstract class UpdateMiniCrudRequest extends FormRequest
$mergeRules = $this->compileValidate('required|string|min:15', $input);
$mergeRules = collect($mergeRules)
->map(function ($rule) {
if (\strpos($rule, 'max:') !== false) {
if (\is_string($rule) && \strpos($rule, 'max:') !== false) {
$max = \intval(str_replace('max:', '', $rule));
return function ($attribute, $value, $fail) use ($max) {
if (\strlen(\strip_tags($value)) > $max) {
@ -80,13 +81,13 @@ abstract class UpdateMiniCrudRequest extends FormRequest
};
}
return $rule;
});
})->all();
$rules = array_merge($rules, [
"data.$iptName.value" => $mergeRules
]);
break;
case InputType::image->value:
$required = $this->isUpdate() ? 'sometimes' : 'required';
$required = $this->isUpdate() ? 'sometimes' : ($input['required'] ? 'required' : 'nullable');
$ipt = $this->data[$iptName];
$max = isset($ipt['dimensionsMax']);
$dim = \is_string($input['dimensions']) ? collect(explode(
@ -99,11 +100,11 @@ abstract class UpdateMiniCrudRequest extends FormRequest
}) : $input['dimensions'];
// * Adapt dimensions
$sizes = (object)[
$sizes = [
'minHeight' => $dim['height'],
'maxHeight' => $dim['height'],
'minWidth' => $dim['width'],
'maxWidth' => $dim['width'],
'minWidth' => $dim['width'],
'maxWidth' => $dim['width'],
];
$rules = array_merge($rules, [
"data.$iptName.value" => [
@ -133,15 +134,10 @@ abstract class UpdateMiniCrudRequest extends FormRequest
case InputType::url->value:
$rules = array_merge($rules, [
"data.$iptName.value" => [
'required', 'url',
$this->compileValidate('url', $input),
// @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]);
}
$this->validateUrl($attribute, $value, $fail);
}
]
]);
@ -160,22 +156,23 @@ abstract class UpdateMiniCrudRequest extends FormRequest
break;
} //end switch
} //end foreach
// @phpstan-ignore-next-line
return $rules;
}
/**
* Undocumented function
* Undocumented function.
*
* @param string|array $inputTypeValidate
* @param array $input
* @return array
* @param string|array<int, string> $inputTypeValidate
* @param array<string, mixed> $input
* @return array<int, mixed>
*/
public function compileValidate(string|array $inputTypeValidate, array $input): array
{
if (\is_string($inputTypeValidate)) {
$inputTypeValidate = explode('|', $inputTypeValidate);
}
/** @var array|string */
/** @var array<int|string, mixed>|string $inputValidate */
$inputValidate = \collect($input)->get('validate', $input);
$inputValidate = \is_string($inputValidate) ? explode('|', $inputValidate) : $inputValidate;
foreach ($inputValidate as $validate) {
@ -184,18 +181,32 @@ abstract class UpdateMiniCrudRequest extends FormRequest
}
}
$test = \collect($inputTypeValidate)->all();
$test = \collect($inputTypeValidate)->sort(function ($valueA, $valueB) {
$valueA = $this->ruleHasToComeFirst($valueA) ? 0 : 2;
$valueB = $this->ruleHasToComeFirst($valueB) ? 1 : 2;
return $valueA - $valueB;
})->unique()->all();
return \collect($inputTypeValidate)->unique()->sort(function ($valueA, $valueB) {
$valueA = $this->ruleHasToComeFirst($valueA) ? 0 : 2;
$valueB = $this->ruleHasToComeFirst($valueB) ? 1 : 2;
return $valueA - $valueB;
})->all();
})->values()->all();
}
/**
* Validate URl
*
* @param string $attribute
* @param mixed $url
* @param \Closure $fail
* @return void
*/
private function validateUrl(string $attribute, mixed $url, \Closure $fail): void
{
try {
if (!is_null($url)) {
$url = is_string($url) ? $url : '';
ToolboxHelper::assertNoInternalUrls($attribute, $url);
ToolboxHelper::assertNoInternalBoUrls($attribute, $url);
}
} catch (ValidationException $e) {
$fail(collect($e->errors())->first()[0]);
}
}
/**

View file

@ -0,0 +1,60 @@
<?php
namespace App\Http\Requests\Bo;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Http\FormRequest;
class UpdateOrderRequest extends FormRequest
{
/**
* Attribute model needed.
*
* @var Model $orderable
*/
private Model $orderableModel;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->orderableModel = collect($this->route()->parameters())
->first(fn($param) => $param instanceof Model);
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'order' => [
'required',
'integer',
'min:1',
sprintf('max:%s', $this->orderableModel->max('order')),
function ($attribute, $value, $fail) {
/** @phpstan-ignore-next-line */
if ($this->orderableModel && intval($value) === $this->orderableModel->order) {
$fail("La valeur de {$attribute} doit être différente de la valeur actuelle.");
}
},
],
];
}
}

View file

@ -11,7 +11,7 @@ class UploadFileRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth()->check() and $this->ajax();
}
@ -19,9 +19,9 @@ class UploadFileRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules()
public function rules(): array
{
return [
'upload' => 'required|image|mimes:jpeg,png,jpg|max:2048'

View file

@ -7,7 +7,6 @@ use App\Models\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rules\Enum;
use Illuminate\Validation\Rules\Password;
class StoreUserRequest extends FormRequest
{
@ -36,7 +35,7 @@ class StoreUserRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -44,14 +43,6 @@ class StoreUserRequest extends FormRequest
'first_name' => 'required|string|min:3|max:255',
'last_name' => 'required|string|min:3|max:255',
'email' => 'required|email:rfc,strict,dns,spoof,filter|unique:users,email',
'password' => [
'required', 'required_with:password_confirmation', 'confirmed', 'max:255', Password::min(8)
->letters()
->mixedCase()
->numbers()
->symbols()
->uncompromised()
],
'role' => ['required', new Enum(RoleEnum::class)],
'published' => 'required|boolean',
];
@ -60,7 +51,7 @@ class StoreUserRequest extends FormRequest
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{
@ -68,7 +59,6 @@ class StoreUserRequest extends FormRequest
'first_name' => trans('validation.attributes.first_name'),
'last_name' => trans('validation.attributes.last_name'),
'email' => trans('validation.attributes.email'),
'password' => trans('validation.attributes.password'),
'role' => trans('validation.attributes.role'),
'published' => trans('validation.custom.publication')
];

View file

@ -4,7 +4,6 @@ namespace App\Http\Requests\Bo\Users;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;
class UpdateUserRequest extends StoreUserRequest
{
@ -26,18 +25,14 @@ class UpdateUserRequest extends StoreUserRequest
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published'),
'password' => $this->input('password') ??
\optional($this->route('user'))->password,
'password_confirmation' => $this->input('password_confirmation') ??
\optional($this->route('user'))->password
'published' => $this->boolean('published'),
]);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -46,15 +41,7 @@ class UpdateUserRequest extends StoreUserRequest
'required',
'email:rfc,strict,dns,spoof,filter',
Rule::unique('users', 'email')->ignore(\optional($this->route('user'))->getRouteKey())
],
'password' => [
'required', 'required_with:password_confirmation', 'confirmed', 'max:255', Password::min(8)
->letters()
->mixedCase()
->numbers()
->symbols()
->uncompromised()
],
]
]);
}
}

View file

@ -18,10 +18,10 @@ class ListenFormRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'country' => $this->post('country') == null ? $this->post('country') : null,
'country' => $this->post('country') ?? null,
'accept_rules' => $this->boolean('accept_rules'),
'send_data' => $this->boolean('send_data'),
]);
@ -30,7 +30,7 @@ class ListenFormRequest extends FormRequest
/**
* Get the validation rules that apply to the request.
*
* @return array
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
@ -40,15 +40,27 @@ class ListenFormRequest extends FormRequest
'last_name' => 'required|string|between:3,100',
'society' => 'present|nullable|string|between:3,255',
'email' => 'required|email:rfc,strict,dns,spoof,filter|max:255',
'phone' => 'present|nullable|phone:FR|max:25',
'postal_code' => 'present|nullable|postal_code:FR|max:25',
'phone' => array_merge(
['present', 'nullable'],
!is_null(request()->input('country'))
? (Country::make(request()->input('country'))->value === Country::france->value
? ['phone:FR', 'max:25']
: ['numeric', 'max:50'])
: ['numeric', 'max:50']
),
'postal_code' => array_merge(
['present', 'nullable'],
!is_null(request()->input('country'))
? (Country::make(request()->input('country'))->value === Country::france->value
? ['postal_code:FR', 'max:25']
: ['numeric', 'max:50'])
: ['numeric', 'max:50']
),
'city' => 'present|nullable|string|between:3,20',
'country' => ['present', 'nullable', new Enum(Country::class)],
'address' => 'present|nullable|string|between:3,255',
'object' => ['required', new Enum(ObjectEnum::class)],
'message' => 'required|min:20|max:35656',
'accept_rules' => 'required|boolean',
'send_data' => 'required|boolean',
];
if (
isset(request()->file) and
@ -66,7 +78,6 @@ class ListenFormRequest extends FormRequest
));
} elseif (isset(request()->file) and (request()->file->getClientMimeType() === "application/pdf")) {
$rules = \array_merge($rules, [
//phpcs:ignore Generic.Files.LineLength.TooLong
'file' => 'present|nullable|mimes:pdf'
]);
} elseif (
@ -90,7 +101,7 @@ class ListenFormRequest extends FormRequest
/**
* Get custom attributes for validator errors.
*
* @return array
* @return array<string, string>
*/
public function attributes(): array
{

View file

@ -0,0 +1,48 @@
<?php
namespace App\Jobs;
use App\Models\ActivityLog;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
/**
* Permanently deletes entries that have been stored for more than one year.
*/
class CleanOldActivities implements ShouldQueue, ShouldBeUnique
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* Create the controller instance.
*
* @param boolean $force
*/
public function __construct(public readonly bool $force = false)
{
}
/**
* Delete entries if it has been stored for more than one year.
*
* @return void
*/
public function handle(): void
{
$query = ActivityLog::query();
if (!$this->force) {
$query->where('created_at', '<', Carbon::now()->subYear());
}
$query->cursor()->each(fn($model) => $model->delete());
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace App\Jobs;
use App\Models\News;
use App\Models\Strip;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
/**
* Update published attribute reading its
* publish_at and unpublish_at attributes.
*/
class UpdatePlanificatedStatus
{
/**
* Called when the job will be executed.
*
* @return void
*/
public function handle(): void
{
collect([News::class, Strip::class])
->each(function (string $model) {
/** @var \Illuminate\Database\Eloquent\Collection<array-key,\App\Models\News|\App\Models\Strip> */
$modelListToPublish = $model::query()
->whereNotNull('publish_at')
->where('publish_at', '<=', Carbon::now())
->where(function ($query) {
$query->whereNull('unpublish_at')
->orWhere('unpublish_at', '>', Carbon::now());
})
->where('published', false)
->get();
Log::debug(__CLASS__ . " models to publish " . $modelListToPublish->count());
$modelListToPublish->each(function ($currentModel) {
$currentModel->published = true;
$currentModel->saveOrFail();
});
/** @var \Illuminate\Database\Eloquent\Collection<array-key,\App\Models\News|\App\Models\Strip> */
$modelListToUnpublish = $model::query()
->whereNotNull('unpublish_at')
->where('unpublish_at', '<=', Carbon::now())
->where('published', true)
->get();
Log::debug(__CLASS__ . " models to unpublish " . $modelListToUnpublish->count());
$modelListToUnpublish->each(function ($currentModel) {
$currentModel->published = false;
$currentModel->saveOrFail();
});
});
}
}

View file

@ -10,33 +10,37 @@ use Illuminate\Support\Collection;
class CollectionHelper
{
/**
* Paginate a collection
* Paginate a collection.
*
* @param \Illuminate\Support\Collection $results
* @param integer $pageSize
* @return \Illuminate\Pagination\LengthAwarePaginator
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Support\Collection<int, TModel> $results
* @param integer $pageSize
* @return \Illuminate\Pagination\LengthAwarePaginator<TModel>
*/
public static function paginate(Collection $results, int $pageSize): LengthAwarePaginator
public static function paginate(Collection $results, int $pageSize): \Illuminate\Pagination\LengthAwarePaginator
{
$page = Paginator::resolveCurrentPage('page');
return self::paginateManually($results, $pageSize, $page);
}
/**
* Paginate a collection
* Paginate a collection.
*
* @param \Illuminate\Support\Collection $results
* @param integer $pageSize
* @param integer $page
* @return \Illuminate\Pagination\LengthAwarePaginator
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Support\Collection<int, TModel> $results
* @param integer $pageSize
* @param integer $page
* @return \Illuminate\Pagination\LengthAwarePaginator<TModel>
*/
public static function paginateManually(Collection $results, int $pageSize, int $page = 1): LengthAwarePaginator
{
public static function paginateManually(
Collection $results,
int $pageSize,
int $page = 1
): \Illuminate\Pagination\LengthAwarePaginator {
$total = $results->count();
return self::paginator($results->forPage($page, $pageSize), $total, $pageSize, $page, [
'path' => Paginator::resolveCurrentPath(),
'path' => Paginator::resolveCurrentPath(),
'pageName' => 'page',
]);
}
@ -44,21 +48,27 @@ class CollectionHelper
/**
* Create a new length-aware paginator instance.
*
* @param \Illuminate\Support\Collection $items
* @param integer $total
* @param integer $perPage
* @param integer $currentPage
* @param array $options
* @return \Illuminate\Pagination\LengthAwarePaginator
* @template TModel of \Illuminate\Database\Eloquent\Model
* @param \Illuminate\Support\Collection<int, TModel> $items
* @param integer $total
* @param integer $perPage
* @param integer $currentPage
* @param array<mixed> $options
* @return \Illuminate\Pagination\LengthAwarePaginator<TModel>
*/
protected static function paginator(Collection $items, int $total, int $perPage, int $currentPage, array $options)
{
protected static function paginator(
Collection $items,
int $total,
int $perPage,
int $currentPage,
array $options
): \Illuminate\Pagination\LengthAwarePaginator {
return Container::getInstance()->makeWith(LengthAwarePaginator::class, [
'items' => $items,
'total' => $total,
'perPage' => $perPage,
'items' => $items,
'total' => $total,
'perPage' => $perPage,
'currentPage' => $currentPage,
'options' => $options
'options' => $options
]);
}
}

View file

@ -5,7 +5,7 @@ namespace App\Lib\Helpers;
class ExceptionsHelper
{
/**
* Handle sentry event
* Handle sentry event.
*
* @param \Sentry\Event $event
* @return null|\Sentry\Event
@ -26,7 +26,7 @@ class ExceptionsHelper
}
/**
* Anonimize Sentry Exception bag
* Anonimize Sentry Exception bag.
*
* @param \Sentry\ExceptionDataBag $exceptionDataBag
* @return \Sentry\ExceptionDataBag
@ -42,7 +42,7 @@ class ExceptionsHelper
}
/**
* Anonymise sentry stacktrace
* Anonymise sentry stacktrace.
*
* @param \Sentry\Stacktrace $stackTrace
* @return \Sentry\Stacktrace
@ -70,7 +70,7 @@ class ExceptionsHelper
}
/**
* Get anonymized sentry params
* Get anonymized sentry params.
*
* @param mixed[] $params
* @return string[]
@ -80,7 +80,7 @@ class ExceptionsHelper
foreach ($params as &$param) {
$type = \strtolower(\gettype($param));
if (\is_string($param)) {
$type = \explode(' ', \trim(strtolower($param)))[0] ?? null;
$type = \explode(' ', \trim(strtolower($param)))[0];
}
switch (true) {
case $type === 'lambda':
@ -103,9 +103,8 @@ class ExceptionsHelper
return $params;
}
/**
* Anonymize at least Sql queries
* Anonymize at least Sql queries.
*
* @param string $message
* @return string
@ -120,14 +119,14 @@ class ExceptionsHelper
}
/**
* Anonymize stack trace
* Anonymize stack trace.
*
* @param \Throwable $e
* @return string
*/
public static function getAnonymizedStackTrace(\Throwable $e): string
{
$projectPath = \realpath(\sprintf('%s/../', \app_path()));
$projectPath = \realpath(\sprintf('%s/../', \app_path())) ?: '';
$traceStack = $e->getTrace();
$traceStr = '';
$maxStackStage = 0;
@ -159,9 +158,9 @@ class ExceptionsHelper
}
/**
* Handle Args
* Handle Args.
*
* @param array $stack
* @param array<string, mixed> $stack
* @return string
*/
public static function handleArgs(array $stack): string

View file

@ -25,8 +25,6 @@ use Illuminate\Support\Str;
* 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
{
@ -40,7 +38,7 @@ class FileStorageHelper
{
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$disk = Storage::disk('uploads');
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
$path = ToolboxHelper::mbReplaceString('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
return $disk->path($path);
}
@ -57,7 +55,7 @@ class FileStorageHelper
if (\strpos($path, 'storage') !== 0) {
return;
}
$path = ToolboxHelper::mbReplace('storage/', '', $path);
$path = ToolboxHelper::mbReplaceString('storage/', '', $path);
if (Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
@ -81,7 +79,7 @@ class FileStorageHelper
if (\strpos($originalPath, 'storage') !== 0) {
return;
}
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
$originalPath = ToolboxHelper::mbReplaceString('storage/', '', $originalPath);
if (Storage::disk('public')->exists($originalPath)) {
Storage::disk('public')->delete($originalPath);
}
@ -105,8 +103,8 @@ class FileStorageHelper
Model $model,
$file,
bool $slugify = false,
string $filename = null,
bool $private = false
string|null $filename = null,
bool $private = false,
): string {
// phpcs:enable
$tableName = $model->getTable();
@ -166,16 +164,16 @@ class FileStorageHelper
public static function storeModelFilesFromHtml(
Model $model,
string $htmlString,
string $oldHtmlString = null
string|null $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))
ToolboxHelper::mbReplaceString('/uploads/', '', \urldecode($path))
));
$htmlString = ToolboxHelper::mbReplace(
$htmlString = ToolboxHelper::mbReplaceString(
$path,
'/' . self::storeFile($model, $fileInfo, true),
$htmlString
@ -216,7 +214,7 @@ class FileStorageHelper
$filesToKeep = \collect(self::onlyUploadedFilesWithFileStorageHelper($newFiles));
$filesToRemove = $oldFiles->diff($filesToKeep);
$filesToRemove->each(function (string $publicStorageFilePath) {
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
$path = ToolboxHelper::mbReplaceString('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
if (Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
@ -233,7 +231,7 @@ class FileStorageHelper
{
$filesToRemove = \collect(self::onlyUploadedFilesWithFileStorageHelper(self::findFilesInHtml($htmlString)));
$filesToRemove->each(function (string $publicStorageFilePath) {
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
$path = ToolboxHelper::mbReplaceString('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
if (Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
@ -244,7 +242,7 @@ class FileStorageHelper
* Find all occurence of files in html
*
* @param string $html
* @return array
* @return array<mixed>
*/
public static function findFilesInHtml(string $html): array
{
@ -259,20 +257,20 @@ class FileStorageHelper
* Filter array to get only uploaded files that exists
* on disk 'public' (using helper storage strategy)
*
* @param array $urls
* @return array
* @param array<int, string> $urls
* @return array<mixed>
*/
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);
$path = (string) \parse_url($url, \PHP_URL_PATH);
return \strpos(\ltrim($path, '/'), 'storage/modelfiles') === 0;
})->filter(function (string $url) {
$path = \parse_url($url, \PHP_URL_PATH);
$path = (string) \parse_url($url, \PHP_URL_PATH);
return Storage::disk('public')
->exists(ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($path), '/')));
->exists(ToolboxHelper::mbReplaceString('storage/', '', \ltrim(\urldecode($path), '/')));
})->all();
}
@ -280,22 +278,22 @@ class FileStorageHelper
* Filter array to get only uploaded files that exists
* on disk 'uploads'
*
* @param array $urls
* @return array
* @param array<int, string> $urls
* @return array<mixed>
*/
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
$host = (string) \parse_url($url, \PHP_URL_HOST);
$path = (string) \parse_url($url, \PHP_URL_PATH);
return ($host === (string) \parse_url(config('app.url'), PHP_URL_HOST) or $host === '') and
\strpos(\ltrim($path, '/'), 'uploads') === 0;
})->filter(function (string $url) {
$path = \parse_url($url, \PHP_URL_PATH);
$path = (string) \parse_url($url, \PHP_URL_PATH);
return Storage::disk('uploads')
->exists(ToolboxHelper::mbReplace('uploads/', '', \ltrim(\urldecode($path), '/')));
->exists(ToolboxHelper::mbReplaceString('uploads/', '', \ltrim(\urldecode($path), '/')));
})->all();
}
@ -459,7 +457,7 @@ class FileStorageHelper
'/\.{2,}/'
], '.', $filename);
// Lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625 .
$filename = mb_strtolower($filename, mb_detect_encoding($filename));
$filename = mb_strtolower($filename, mb_detect_encoding($filename) ?: null);
// * ".file-name.-" becomes "file-name"
$filename = trim($filename, '.-');
return $filename;
@ -468,7 +466,7 @@ class FileStorageHelper
/**
* Remove all model files for the given Model.
*
* @param Model $model
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public static function removeModelFiles(Model $model): void

View file

@ -22,10 +22,10 @@ use Symfony\Component\Finder\SplFileInfo;
class ToolboxHelper
{
/**
* Run a terminal command and gives the output
* Run a terminal command and gives the output.
*
* @param array|string $command The command to execute on terminal.
* @param boolean $throw Wether to throw en esception on failure or not.
* @param array<string>|string $command The command to execute on terminal.
* @param boolean $throw Wether to throw en esception on failure or not.
* @return string|false Return false on failure only if $throw is false.
* @phpcs:disable Squiz.Commenting.FunctionComment.EmptyThrows
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
@ -36,7 +36,7 @@ class ToolboxHelper
* @throws \LogicException
* @throws \RuntimeException If the command fails.
*/
public static function runConsoleCommand(array|string $command, bool $throw = true): string | false
public static function runConsoleCommand(array|string $command, bool $throw = true): string|false
{
// phpcs:enable
$process = \Illuminate\Support\Facades\Process::command($command)->run();
@ -54,7 +54,6 @@ class ToolboxHelper
/**
* @param array<int|string, mixed> $array1
* @param array<int|string, mixed> $array2
*
* @return array<int|string, mixed>
*/
public static function arrayMergeRecursiveDistinct(array &$array1, array &$array2): array
@ -67,18 +66,17 @@ class ToolboxHelper
$merged[$key] = $value;
}
}
return $merged;
}
/**
* Validate recaptcha
* Validate recaptcha.
*
* @param \Illuminate\Http\Request $request
* @param boolean $isV3
* @return void
*/
public static function validateRecaptcha(Request $request, bool $isV3 = true)
public static function validateRecaptcha(Request $request, bool $isV3 = true): void
{
Validator::validate($request->all(), [
'g-recaptcha-response' => [
@ -130,7 +128,7 @@ class ToolboxHelper
* 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..)
* only cloud hosted medias (youtube, spotify etc..).
*
* @param string $input
* @return string
@ -142,7 +140,7 @@ class ToolboxHelper
}
/**
* Assert That no Back Office url is present on txt
* Assert That no Back Office url is present on txt.
*
* @param string $field
* @param string $text
@ -185,7 +183,7 @@ class ToolboxHelper
}
/**
* Assert That only external url is present on txt
* Assert That only external url is present on txt.
*
* @param string $field
* @param string $text
@ -228,13 +226,14 @@ class ToolboxHelper
}
/**
* Mutltibyte string replace
* Mutltibyte string replace.
*
* @param array|string $search
* @param array|string $replace
* @param array|string $subject
* @param integer $count
* @return array|string|false
* @param array<string>|string $search
* @param array<string>|string $replace
* @param array<string>|string $subject
* @param integer $count
* @return array<string>|string|false
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public static function mbReplace(
array|string $search,
@ -248,37 +247,58 @@ class ToolboxHelper
if (is_array($subject)) {
// Call mb_replace for each single string in $subject .
foreach ($subject as &$string) {
$string = &self::mbReplace($search, $replace, $string, $count);
$string = &self::mbReplace($search, $replace, $string, $count) ?: '';
}
return $subject;
} elseif (is_array($search)) {
if (!is_array($replace)) {
foreach ($search as &$string) {
$subject = self::mbReplace($string, $replace, $subject, $count);
$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);
$currentSearch = current($search);
$currentReplace = current($replace);
if ($currentSearch === false || $currentReplace === false) {
break;
}
$result = self::mbReplace($currentSearch, $currentReplace, $subject, $count);
$subject = is_string($result) ? $result : '';
next($search);
next($replace);
}
}
} else {
$parts = mb_split(preg_quote($search), $subject);
$count = count($parts) - 1;
$subject = implode($replace, $parts);
$parts = mb_split(preg_quote($search), $subject) ?: [];
$count = (int) count($parts) - 1;
$subject = implode(is_array($replace) ? '' : $replace, $parts);
} //end if
return $subject;
}
/**
* Multibyte string replace (string only version).
*
* @param string $search
* @param string $replace
* @param string $subject
* @return string
*/
public static function mbReplaceString(string $search, string $replace, string $subject): string
{
$parts = mb_split(preg_quote($search), $subject) ?: [];
return implode($replace, $parts);
}
/**
* 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
* @param string $table
* @param string $field
* @param string|integer|float|boolean|null|array<mixed> $value
* @param integer|null $id
* @param callable|null $query
* @return void
* @throws \Illuminate\Validation\ValidationException If the field is not unique.
*/
@ -288,28 +308,32 @@ class ToolboxHelper
string|int|float|bool|null|array $value,
?int $id = null,
?callable $query = null
) {
): void {
if (!$query) {
Validator::make([$field => $value], [
/** @phpstan-ignore-next-line */
self::mbReplace('.', '\.', $field) => Rule::unique($table, $field)->ignore($id),
], [
self::mbReplace('.', '\.', "{$field}.unique")
=> trans('crud.libs.toolbox.assertFieldIsUnique', ['attribute' => $field, 'value' => $value])
/** @phpstan-ignore-next-line */
self::mbReplace('.', '\.', "{$field}.unique") => trans('crud.libs.toolbox.assertFieldIsUnique', [
'attribute' => $field,
'value' => is_array($value) ? implode(', ', array_map('strval', $value)) : (string) $value,
])
])->validate();
return;
}
Validator::make([$field => $value], [
$field => Rule::unique($table)->where($query)->ignore($id),
$field => Rule::unique($table)->where(\Closure::fromCallable($query))->ignore($id),
], [
$field . '.unique' => trans(
'crud.libs.toolbox.assertFieldIsUnique',
['attribute' => $field, 'value' => $value]
)
$field . '.unique' => trans('crud.libs.toolbox.assertFieldIsUnique', [
'attribute' => $field,
'value' => is_array($value) ? implode(', ', array_map('strval', $value)) : (string) $value,
])
])->validate();
}
/**
* Get original polyfill with autotranslate behavior
* Get original polyfill with autotranslate behavior.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $attribute
@ -335,7 +359,7 @@ class ToolboxHelper
}
/**
* Dynamic model query
* Dynamic model query.
*
* @param string $defaultLocale
* @param \Illuminate\Contracts\Database\Eloquent\Builder $q
@ -348,9 +372,9 @@ class ToolboxHelper
Builder $q,
string $column,
string $value
): Builder {
): \Illuminate\Contracts\Database\Eloquent\Builder {
$currentLocale = app()->currentLocale();
$locales = collect(config('app.locales'))
$locales = collect((array) config('app.locales', []))
->mapWithKeys(fn (string $locale) => [$locale => $locale]);
if (!$locales->has($defaultLocale)) {
// * Remove default locale.
@ -376,17 +400,18 @@ class ToolboxHelper
}
/**
* Generates an array from a dot separated string
* Generates an array from a dot separated string.
*
* @param string $path
* @param mixed $value
* @param string $separator
* @return array
* @param string $path
* @param mixed $value
* @param string|null $separator
* @return array<mixed>
*/
public static function dotStringToNestedArray(string $path, mixed $value, string $separator = '.'): array
public static function dotStringToNestedArray(string $path, mixed $value, string|null $separator = null): array
{
$arr = $value;
$keys = array_reverse(explode($separator, $path));
$arr = $value;
$separator = $separator ?: '.';
$keys = array_reverse(explode($separator, $path));
foreach ($keys as $key) {
$arr = [$key => $arr];
@ -395,10 +420,10 @@ class ToolboxHelper
}
/**
* Convert deeply an object to array
* Convert deeply an object to array.
*
* @param mixed $input
* @return array
* @return array<mixed>
* @throws \RuntimeException If $input var is a scalar value.
*/
public static function objectToArray(mixed $input): array
@ -407,7 +432,7 @@ class ToolboxHelper
if (!(is_object($input) or is_array($input))) {
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
}
$ret = (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)) ?
@ -417,7 +442,7 @@ class ToolboxHelper
}
/**
* Convert deeply an array to object
* Convert deeply an array to object.
*
* @param mixed $input
* @return object
@ -429,25 +454,25 @@ class ToolboxHelper
if (!(is_object($input) or is_array($input))) {
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
}
$ret = (object)$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::arrayToObject($item) : $item;
}
return $ret;
return (object) $ret;
}
/**
* Validate picture
* Validate picture.
*
* @param string $attribute
* @param string|null $value
* @param callable $fail
* @param object $sizes
* @param string $attribute
* @param string|null $value
* @param callable $fail
* @param array{minWidth: int, maxWidth: int, minHeight: int, maxHeight: int} $sizes
* @return void
*/
public static function validatePicture(string $attribute, string|null $value, callable $fail, object $sizes): void
public static function validatePicture(string $attribute, string|null $value, callable $fail, array $sizes): void
{
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
$fail(trans(':attribute n\'existe pas dans le système de fichier', [
@ -474,29 +499,29 @@ class ToolboxHelper
$height = intval($dimensions[1]);
$xMessage = trans(
":attribute la largeur doit être comprise entre {$sizes->minWidth}px et {$sizes->maxWidth}px"
":attribute la largeur doit être comprise entre {$sizes['minWidth']}px et {$sizes['maxWidth']}px"
);
if ($sizes->minWidth === $sizes->maxWidth) {
$xMessage = trans(":attribute la largeur doit être de {$sizes->minWidth}px");
if ($sizes['minWidth'] === $sizes['maxWidth']) {
$xMessage = trans(":attribute la largeur doit être de {$sizes['minWidth']}px");
}
$yMessage = trans(
":attribute la hauteur doit être comprise entre {$sizes->minHeight}px et {$sizes->maxHeight}px"
":attribute la hauteur doit être comprise entre {$sizes['minHeight']}px et {$sizes['maxHeight']}px"
);
if ($sizes->minHeight === $sizes->maxHeight) {
$yMessage = trans(":attribute la hauteur doit être de {$sizes->minHeight}px");
if ($sizes['minHeight'] === $sizes['maxHeight']) {
$yMessage = trans(":attribute la hauteur doit être de {$sizes['minHeight']}px");
}
if (($width < $sizes->minWidth) or ($width > $sizes->maxWidth)) {
if (($width < $sizes['minWidth']) or ($width > $sizes['maxWidth'])) {
$fail($xMessage);
}
if (($height < $sizes->minHeight) or ($height > $sizes->maxHeight)) {
if (($height < $sizes['minHeight']) or ($height > $sizes['maxHeight'])) {
$fail($yMessage);
}
} //end if
}
/**
* Get the file full path
* Get the file full path.
*
* @param string $value
* @param boolean $useStorage
@ -510,19 +535,19 @@ class ToolboxHelper
}
/**
* Get the file mimetype
* Get the file mimetype.
*
* @param string $value
* @param boolean $useStorage
* @return string|false
*/
private static function getUploadedFileMimeType(string $value, bool $useStorage)
private static function getUploadedFileMimeType(string $value, bool $useStorage): string|false
{
return !$useStorage ? File::mimeType($value) : Storage::mimeType($value);
}
/**
* Fetch class list from a specific namespace
* Fetch class list from a specific namespace.
*
* @param string $namespace
* @return array<string> An array of classe namespaces
@ -536,7 +561,7 @@ class ToolboxHelper
}
/**
* Get all classes from a specific namespace that implement a specific interface
* Get all classes from a specific namespace that implement a specific interface.
*
* @param string $namespace
* @param string $interface
@ -546,7 +571,7 @@ class ToolboxHelper
{
return Arr::where(
static::getClassesUsingNamespace($namespace),
fn (string $class_namespace) => \collect(class_implements($class_namespace, true))->filter()
fn (string $class_namespace) => \collect(class_implements($class_namespace, true) ?: [])->filter()
->contains(fn (string $class_interface) => $class_interface === $interface)
);
}
@ -554,9 +579,9 @@ class ToolboxHelper
/**
* Get validated pagination from request.
*
* @param integer $default
* @param string $field
* @param string $enumPath
* @param integer $default
* @param string $field
* @param class-string<\UnitEnum> $enumPath
* @return integer
*/
public static function getValidatedEnum(int $default, string $field, string $enumPath): int

View file

@ -18,7 +18,7 @@ class SendConfirmationMail extends Mailable
use SerializesModels;
/**
* @var \App\Mail\Contact
* @var \stdClass
*/
private \stdClass $data;
@ -27,11 +27,9 @@ class SendConfirmationMail extends Mailable
*
* @param \stdClass $data
* @return void
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function __construct(\stdClass $data)
{
// @phpstan-ignore-next-line
$this->data = clone $data;
$this->sanitizeStringInputs();
}
@ -48,11 +46,10 @@ class SendConfirmationMail extends Mailable
*/
private function sanitizeStringInputs(): void
{
// @phpstan-ignore-next-line
$this->data = (object)Arr::map((array)$this->data, function ($el) {
$this->data = (object) Arr::map((array) $this->data, function ($el) {
if (is_string($el)) {
$el = \htmlspecialchars(\strip_tags(Blade::render(
(string)Markdown::parse($el)
(string) Markdown::parse($el)
)));
$el = Str::of($el)->replaceMatches(
'/[^\p{L}0-9\n\s\@\.\:\-\_\?\!\;\(\)\+\-\/\\\=]+/us',
@ -92,24 +89,3 @@ class SendConfirmationMail extends Mailable
);
}
}
/**
* @property \App\Enums\Contact\ObjectEnum $type
* @property string|null $first_name
* @property string $last_name
* @property string|null $phone
* @property string $email
* @property string|null $address
* @property string|null $city
* @property string|null $postal_code
* @property string $message
* @property boolean $terms
* @property \Illuminate\Http\UploadedFile|null $file
* @property \App\Models\Product|null $product
* @property \Carbon\Carbon|null $expiration_date
* @property integer|null $batch_number
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
*/
class ContactConfirmation extends \stdClass
{
}

View file

@ -20,7 +20,7 @@ class SendContactMail extends Mailable
use SerializesModels;
/**
* @var \App\Mail\Contact
* @var \stdClass
*/
private \stdClass $data;
@ -33,13 +33,12 @@ class SendContactMail extends Mailable
*/
public function __construct(\stdClass $data)
{
// @phpstan-ignore-next-line
$this->data = clone $data;
$this->sanitizeStringInputs();
}
/**
* Sanitizes user message
* Sanitizes user message.
*
* ! This is not recursive !
* * Prevent xss injection via markdown interpretation.
@ -50,11 +49,10 @@ class SendContactMail extends Mailable
*/
private function sanitizeStringInputs(): void
{
// @phpstan-ignore-next-line
$this->data = (object)Arr::map((array)$this->data, function ($el) {
$this->data = (object) Arr::map((array) $this->data, function ($el) {
if (is_string($el)) {
$el = \htmlspecialchars(\strip_tags(Blade::render(
(string)Markdown::parse($el)
(string) Markdown::parse($el)
)));
$el = Str::of($el)->replaceMatches(
'/[^\p{L}0-9\n\s\@\.\:\-\_\?\!\;\(\)\+\-\/\\\=]+/us',
@ -110,24 +108,3 @@ class SendContactMail extends Mailable
return $attachments;
}
}
/**
* @property \App\Enums\Contact\ObjectEnum $type
* @property string|null $first_name
* @property string $last_name
* @property string|null $phone
* @property string $email
* @property string|null $address
* @property string|null $city
* @property string|null $postal_code
* @property string $message
* @property boolean $terms
* @property \Illuminate\Http\UploadedFile|null $file
* @property \App\Models\Product|null $product
* @property \Carbon\Carbon|null $expiration_date
* @property integer|null $batch_number
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
*/
class Contact extends \stdClass
{
}

View file

@ -3,25 +3,20 @@
namespace App\Models;
use App\Enums\ActivityLogs\ActivityLogsEventEnum;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Str;
/**
* @property string $model Target model.
* @property string $model_id Id of the target model.
* @property \App\Enums\ActivityLogs\ActivityLogsEventEnum $event Event of this activity (ActivityLogsEventEnum).
* @property array $data Changes.
* @property array<string, mixed> $data Changes.
* @property-read \Illuminate\Support\Carbon $created_at Created date.
*
* @property-read \App\Models\User $user User BelongsTo relation.
*/
class ActivityLog extends Model
{
use HasFactory;
use Notifiable;
/**
* Indicates if the model should be timestamped.
*
@ -32,7 +27,7 @@ class ActivityLog extends Model
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
* @var list<string>
*/
protected $fillable = [
'is_anonymous',
@ -92,17 +87,19 @@ class ActivityLog extends Model
* @param self $activity
* @param \Illuminate\Database\Eloquent\Model $model
* @param \App\Enums\ActivityLogs\ActivityLogsEventEnum $eventEnum
* @return array
* @return array<string, string>
*/
public static function getChangedColumns(self $activity, Model $model, ActivityLogsEventEnum $eventEnum): array
{
$modelClassName = $activity->model_class;
$modelTarget = new $modelClassName();
/** Get type of each fields of the target model */
/** @var \Illuminate\Database\Eloquent\Model|null $targetModel */
$targetModel = $activity->model_class::where(
(new $modelClassName())->getRouteKeyName(),
$targetModel = ($modelTarget instanceof \Illuminate\Database\Eloquent\Model) ? $activity->model_class::where(
$modelTarget->getRouteKeyName(),
$activity->model_id
)->first();
)->first() : null;
if (\is_null($targetModel)) {
return [];
@ -122,7 +119,7 @@ class ActivityLog extends Model
/**
* Get a value type as a string
* ! Use this for display purpose only
* ! Use this for display purpose only.
*
* @param mixed $value
* @return string
@ -137,13 +134,13 @@ class ActivityLog extends Model
// phpcs:ignore PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
case 'string':
return match (true) {
Str::length(\strip_tags($value)) !== Str::length($value) => 'html',
Str::startsWith($value, 'storage/modelfiles') => 'file',
Str::isUuid($value) => 'uuid',
Str::isUlid($value) => 'ulid',
Str::isUrl($value) => 'url',
Str::isMatch('/^[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]$/', $value) => 'youtube_video_id',
\is_numeric($value) => 'numeric',
Str::length(\strip_tags($value)) !== Str::length($value) => 'html',
Str::startsWith($value, 'storage/modelfiles') => 'file',
Str::isUuid($value) => 'uuid',
Str::isUlid($value) => 'ulid',
Str::isUrl($value) => 'url',
Str::isMatch('/^[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]$/', $value) => 'youtube_video_id',
\is_numeric($value) => 'numeric',
Str::isJson($value) and
(Str::startsWith($value, '[') or Str::startsWith($value, '{')) => 'json',
default => 'string'
@ -165,12 +162,12 @@ class ActivityLog extends Model
} //end switch
}
// * RELATIONS
// * RELATIONS.
/**
* User BelongsTo relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\User,$this>
*/
public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{

142
app/Models/Aisle.php Normal file
View file

@ -0,0 +1,142 @@
<?php
namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Traits\Models\ActivityLog;
use App\Traits\Models\Orderable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\ValidationException;
class Aisle extends Model
{
use ActivityLog;
use Orderable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'title',
'text',
'picture',
'picture_alt',
'picture_title',
'published',
'network_id',
'order',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'published' => 'boolean',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
self::setOrder($model);
self::manageFields($model);
});
static::updating(function (self $model) {
self::manageFields($model);
});
static::updated(function (self $model) {
FileStorageHelper::removeOldFile($model, 'picture');
});
static::deleting(function (self $model) {
self::assertLimitPublishedModels($model, true);
});
static::deleted(function (self $model) {
FileStorageHelper::removeFile($model, 'picture');
self::setOrder($model, true);
});
}
// * METHODS.
/**
* Manage model fields.
*
* @param self $model
* @return void
*/
private static function manageFields(self $model): void
{
// * ASSERTIONS
self::assertLimitPublishedModels($model);
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
/**
* Check if the limit of published models is reached.
*
* @param self $model
* @param boolean $isDeletion
* @throws \Illuminate\Validation\ValidationException If the limit of published models is reached.
* @return void
*/
private static function assertLimitPublishedModels(self $model, bool $isDeletion = false)
{
$count = self::query()
->where('published', true)
->where('network_id', $model->network_id)
->count();
$updatePublished = !$isDeletion && $model->published && !$model->getOriginal('published');
if (
(!$model->published && $count <= 1) ||
($updatePublished && $count >= 4) ||
($isDeletion && $count === 1)
) {
throw ValidationException::withMessages([
'Il doit y avoir entre 1 et 4 éléments attachés à chaque réseau.'
]);
}
}
/**
* Group ordering by network_id.
*
* @return string
*/
public function getOrderGroupField(): string
{
return 'network_id';
}
// * RELATIONS.
/**
* The network that belongs to the logo.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\Network,$this>
*/
public function network(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Network::class);
}
/**
* Associated brands.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\Brand,$this>
*/
public function brands(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Brand::class);
}
}

119
app/Models/Brand.php Normal file
View file

@ -0,0 +1,119 @@
<?php
namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Traits\Models\ActivityLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\ValidationException;
class Brand extends Model
{
use ActivityLog;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'text',
'picture',
'picture_alt',
'picture_title',
'link',
'published',
'aisle_id'
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'published' => 'bool',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
self::manageFields($model);
});
static::updating(function (self $model) {
self::manageFields($model);
});
static::updated(function (self $model) {
FileStorageHelper::removeOldFile($model, 'picture');
});
static::deleting(function (self $model) {
self::assertLimitPublishedModels($model, true);
});
static::deleted(function (self $model) {
FileStorageHelper::removeFile($model, 'picture');
});
}
// * METHODS.
/**
* Manage model fields.
*
* @param self $model
* @return void
*/
private static function manageFields(self $model): void
{
// * ASSERTIONS.
self::assertLimitPublishedModels($model);
// * TRANSFORMATIONS.
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
/**
* Check if the limit of published models is reached.
*
* @param self $model
* @param boolean $isDeletion
* @throws \Illuminate\Validation\ValidationException If the limit of published models is reached.
* @return void
*/
private static function assertLimitPublishedModels(self $model, bool $isDeletion = false)
{
$count = self::query()
->where('published', true)
->where('aisle_id', $model->aisle_id)
->count();
$updatePublished = !$isDeletion && $model->published && !$model->getOriginal('published');
if (
$count !== 0 &&
((!$model->published && $count <= 1) ||
($updatePublished && $count >= 5) ||
($isDeletion && $count === 1))
) {
throw ValidationException::withMessages([
'Il doit y avoir entre 1 et 5 éléments publiés simultanément.'
]);
}
}
// * RELATIONS.
/**
* Associated aisle.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\Aisle,$this>
*/
public function aisle(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Aisle::class);
}
}

102
app/Models/Carousel.php Normal file
View file

@ -0,0 +1,102 @@
<?php
namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Lib\Helpers\ToolboxHelper;
use App\Traits\Models\ActivityLog;
use App\Traits\Models\Orderable;
use Illuminate\Database\Eloquent\Model;
/**
* @property-read int $id Id.
* @property string $title Title.
* @property array $media Medias of the carousel.
* @property-read \Carbon\Carbon $created_at Created date.
* @property-read \Carbon\Carbon $updated_at Updated date.
*
* @property-read \App\Models\ActivityLog $activityLogs Activities logs One-to-many relationship.
*/
class Carousel extends Model
{
use ActivityLog;
use Orderable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'section_id',
'title',
'media',
'order',
'published',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'media' => 'array',
'published' => 'boolean',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
$otherCarousels = self::query()
->whereRelation('section', 'id', $model->section->id)
->count();
if ($otherCarousels > 4) {
throw new \RuntimeException('Creating more than 5 carousels is not allowed');
}
self::setOrder($model);
});
static::updated(function (self $model) {
FileStorageHelper::removeOldFiles(
data_get(ToolboxHelper::getOriginal($model, 'media'), 'pictures.*.path', ['']),
data_get($model->media, 'pictures.*.path', [''])
);
});
static::deleted(function (self $model) {
FileStorageHelper::removeOldFiles(
data_get($model->media, 'pictures.*.path', ['']),
['']
);
self::setOrder($model, true);
});
}
// * METHODS.
/**
* Group ordering by section_id.
*
* @return string
*/
public function getOrderGroupField(): string
{
return 'section_id';
}
// * RELATIONSHIPS.
/**
* Get the sections that owns the Carousel
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\Section,$this>
*/
public function section(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Section::class);
}
}

View file

@ -26,12 +26,13 @@ use Illuminate\Database\Eloquent\Model;
class HistoricalMilestone extends Model
{
use ActivityLog;
/** @use HasFactory<\Database\Factories\HistoricalMilestoneFactory> */
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
* @var list<string>
*/
protected $fillable = [
'title',
@ -78,7 +79,7 @@ class HistoricalMilestone extends Model
});
}
// * METHODS
// * METHODS.
/**
* Manage model fields.

View file

@ -18,12 +18,13 @@ use Illuminate\Database\Eloquent\Model;
class JobVideo extends Model
{
use ActivityLog;
/** @use HasFactory<\Database\Factories\JobVideoFactory> */
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
* @var list<string>
*/
protected $fillable = [
'title',

View file

@ -21,12 +21,13 @@ use Illuminate\Database\Eloquent\Model;
class Logo extends Model
{
use ActivityLog;
/** @use HasFactory<\Database\Factories\LogoFactory> */
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
* @var list<string>
*/
protected $fillable = [
'label',
@ -57,7 +58,7 @@ class Logo extends Model
});
}
// * METHODS
// * METHODS.
/**
* Manage model fields.
@ -70,12 +71,12 @@ class Logo extends Model
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
// * RELATIONS
// * RELATIONS.
/**
* The sites that belong to the logo.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<\App\Models\Site,$this>
*/
public function sites(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
{

163
app/Models/Network.php Normal file
View file

@ -0,0 +1,163 @@
<?php
namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Lib\Helpers\ToolboxHelper;
use App\Traits\Models\ActivityLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class Network extends Model
{
use ActivityLog;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'seo_title',
'seo_description',
'name',
'slug',
'title',
'subtitle',
'picture',
'picture_alt',
'picture_title',
'button_text',
'order',
'published',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'published' => 'bool',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
self::setOrder($model);
self::manageFields($model);
});
static::updating(function (self $model) {
self::manageFields($model);
});
static::updated(function (self $model) {
FileStorageHelper::removeOldFile($model, 'picture');
});
static::deleting(function (self $model) {
self::assertLimitPublishedModels($model, true);
});
static::deleted(function (self $model) {
FileStorageHelper::removeFile($model, 'picture');
});
}
// * METHODS.
/**
* Manage model fields.
*
* @param self $model
* @return void
*/
private static function manageFields(self $model): void
{
// * ASSERTIONS.
self::assertLimitPublishedModels($model);
self::assertFieldIsUnique('name', $model->name, $model->id);
self::assertFieldIsUnique('slug', Str::slug($model->name), $model->id);
// * TRANSFORMATIONS.
self::setSlug($model, $model->name);
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
/**
* Set the slug.
*
* @param self $model
* @param string $original
*
* @return void
*/
private static function setSlug(self $model, string $original): void
{
$model->slug = Str::slug($original);
}
/**
* Set order after the last element of the list.
*
* @param self $model
* @return void
*/
private static function setOrder(self $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): void
{
$table = (new self())->getTable();
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
}
/**
* Check if the limit of published models is reached.
*
* @param self $model
* @param boolean $isDeletion
* @throws \Illuminate\Validation\ValidationException If the limit of published models is reached.
* @return void
*/
private static function assertLimitPublishedModels(self $model, bool $isDeletion = false)
{
$count = self::query()->where('published', true)->count();
$updatePublished = !$isDeletion && $model->published && !$model->getOriginal('published');
if (
(!$model->published && $count <= 1) ||
($updatePublished && $count >= 5) ||
($isDeletion && $count === 1)
) {
throw ValidationException::withMessages([
'Il doit y avoir entre 1 et 5 éléments publiés simultanément.'
]);
}
}
// * RELATIONS.
/**
* The aisles that belong to the logo.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\Aisle,$this>
*/
public function aisles(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Aisle::class);
}
}

View file

@ -5,42 +5,46 @@ namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Lib\Helpers\ToolboxHelper;
use App\Traits\Models\ActivityLog;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use App\Traits\Models\PlanificatedStatus;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Spatie\Sitemap\Contracts\Sitemapable;
use Uwil\SitemapGenerator\Lib\SitemapHelper;
/**
* @property string $seo_title SEO title.
* @property string $seo_description SEO description.
* @property string $title Title.
* @property string $slug Slug of the title.
* @property string $introduction WYSIWYG - Introduction.
* @property string|null $content WYSIWYG - Content.
* @property string|null $linkedin_url Url of the linkedin related post.
* @property string $thumbnail Path of the thumbnail.
* @property string $thumbnail_alt Thumbnail alt attribute.
* @property string $thumbnail_title Thumbnail title attribute.
* @property string $picture Path of the picture.
* @property string $picture_alt Picture alt attribute..
* @property string $picture_title Picture title attribute.
* @property integer $order Order.
* @property boolean $published Publication status.
* @property \Carbon\Carbon|null $publish_at Publication date.
* @property \Carbon\Carbon|null $unpublish_at Unpublication status update date.
* @property-read \Carbon\Carbon $created_at Created date.
* @property-read \Carbon\Carbon $updated_at Updated date.
* @property int $id
* @property string $seo_title SEO title.
* @property string $seo_description SEO description.
* @property string $title Title.
* @property string $slug Slug of the title.
* @property string $introduction WYSIWYG - Introduction.
* @property string|null $content WYSIWYG - Content.
* @property string|null $linkedin_url Url of the linkedin related post.
* @property string $thumbnail Path of the thumbnail.
* @property string $thumbnail_alt Thumbnail alt attribute.
* @property string $thumbnail_title Thumbnail title attribute.
* @property string $picture Path of the picture.
* @property string $picture_alt Picture alt attribute..
* @property string $picture_title Picture title attribute.
* @property integer $order Order.
* @property boolean $published Publication status.
* @property \Carbon\Carbon|null $publish_at Publication date.
* @property \Carbon\Carbon|null $unpublish_at Unpublication status update date.
* @property \Carbon\Carbon $displayed_date News dipslayed date.
* @property-read \Carbon\Carbon $created_at Created date.
* @property-read \Carbon\Carbon $updated_at Updated date.
*
* @property-read \App\Models\ActivityLog $activityLogs Activities logs One-to-many relationship.
*/
class News extends Model
class News extends Model implements Sitemapable
{
use ActivityLog;
use HasFactory;
use PlanificatedStatus;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
* @var list<string>
*/
protected $fillable = [
'seo_title',
@ -60,6 +64,7 @@ class News extends Model
'published',
'publish_at',
'unpublish_at',
'displayed_date',
];
/**
@ -68,9 +73,10 @@ class News extends Model
* @var array<string, string>
*/
protected $casts = [
'published' => 'bool',
'publish_at' => 'datetime',
'unpublish_at' => 'datetime',
'published' => 'bool',
'publish_at' => 'datetime',
'unpublish_at' => 'datetime',
'displayed_date' => 'datetime',
];
/**
@ -96,7 +102,7 @@ class News extends Model
});
}
// * METHODS
// * METHODS.
/**
* Manage model fields.
@ -163,50 +169,15 @@ class News extends Model
}
/**
* Adjusts model status using current status and publish dates
* To sitemap tag method.
*
* @param self $model
* @return void
* @return \Spatie\Sitemap\Tags\Url|string|array<int|string, mixed>
*/
private static function makeStatusSense(self $model): void
public function toSitemapTag(): \Spatie\Sitemap\Tags\Url | string | array
{
/** @var \Carbon\Carbon|null */
$publish_at = $model->publish_at;
/** @var \Carbon\Carbon|null */
$unpublish_at = $model->unpublish_at;
$wantedStatus = $model->published;
if ($publish_at or $unpublish_at) {
$model->published = $model->planificated_status;
}
if ($wantedStatus !== $model->published) {
$previousMessage = session()->get('bo.info', '');
session()->flash('bo.info', \trans(
'La publication est modifiée en concordance avec les dates enregistrées.
Pour modifier l\'état de publication, veuillez modifier ou enlever les dates correspondantes.'
) . " \n{$previousMessage}");
}
}
/**
* Getter the current status following planification dates planificated_status
*
* @return boolean
*/
public function getPlanificatedStatusAttribute(): bool
{
/** @var \Carbon\Carbon|null */
$publish_at = $this->publish_at;
/** @var \Carbon\Carbon|null */
$unpublish_at = $this->unpublish_at;
if ($publish_at and $unpublish_at) {
return $unpublish_at->greaterThanOrEqualTo(now()) and $publish_at->lessThan(now());
}
if ($publish_at) {
return $publish_at->lessThan(now());
}
if ($unpublish_at) {
return $unpublish_at->greaterThanOrEqualTo(now());
}
return false;
$model = $this;
$route = 'fo.news.show';
$params = ['publishedNews' => $model];
return SitemapHelper::generateUrl($route, $params, $model);
}
}

View file

@ -2,6 +2,7 @@
namespace App\Models;
use App\Enums\CkEditorConfigName;
use App\Enums\InputType;
use App\Enums\Sections\PageSectionEnum;
use App\Lib\Helpers\FileStorageHelper;
@ -11,12 +12,14 @@ use App\Traits\Models\MiniCrudModel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use App\Models\StaticPage;
use App\Enums\StaticPageType;
/**
* @property \App\Enums\Sections\PageSectionEnum $section Slider that contains the slide.
* @property string $h2_title Title.
* @property string $text WYSIWYG - Content.
* @property string $data Minicrud content.
* @property array $data Minicrud content.
* @property-read \Carbon\Carbon $created_at Created date.
* @property-read \Carbon\Carbon $updated_at Updated date.
*
@ -26,13 +29,14 @@ use Illuminate\Support\Str;
class Section extends Model
{
use ActivityLog;
/** @use HasFactory<\Database\Factories\SectionFactory> */
use HasFactory;
use MiniCrudModel;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
* @var list<string>
*/
protected $fillable = [
'section',
@ -51,8 +55,8 @@ class Section extends Model
* @var array<string, string>
*/
protected $casts = [
'section' => \App\Enums\Sections\PageSectionEnum::class,
'data' => 'object',
'section' => PageSectionEnum::class,
'data' => 'array',
];
/**
@ -73,6 +77,7 @@ class Section extends Model
$model->text = FileStorageHelper::storeModelFilesFromHtml($model, $model->text);
});
static::updated(function (self $model) {
$model->minicrudUpdated();
FileStorageHelper::removeOldModelFilesFromHtml(
$model->text,
ToolboxHelper::getOriginal($model, 'text')
@ -83,310 +88,22 @@ class Section extends Model
});
}
// * METHODS
/**
* Get MiniCrud bloc for home_missions section.
*
* @param array $data
* @param string $img
* @param string $imgAlt
* @param string $imgTitle
* @param integer $width
* @param integer $height
* @param string $url
* @param integer $keyValueSites
* @param integer $keyValueJobs
* @return array
*/
public static function getHomeMissionsBloc(
array $data,
string $img,
string $imgAlt,
string $imgTitle,
int $width,
int $height,
string $url,
int $keyValueSites,
int $keyValueJobs
): array {
$data = self::emptyPictureBloc($data, $img, $imgAlt, $imgTitle, $width, $height);
$data = self::emptyPictureLinkBloc($data, $url);
$data = self::emptyKeyNumberBloc($data, 'sites', $keyValueSites);
$data = self::emptyKeyNumberBloc($data, 'métiers', $keyValueJobs);
return $data;
}
/**
* Get MiniCrud bloc for home_ambition section.
*
* @param array $data
* @return array
*/
public static function getHomeAmbitionBloc(array $data): array
{
return self::emptyButtonBooleanBloc($data, 'On se Dévoile');
}
/**
* Get MiniCrud bloc for home_team section.
*
* @param array $data
* @param string $img
* @param string $imgAlt
* @param string $imgTitle
* @param integer $width
* @param integer $height
* @param string $url
* @return array
*/
public static function getHomeTeamBloc(
array $data,
string $img,
string $imgAlt,
string $imgTitle,
int $width,
int $height,
string $url
): array {
$data = self::emptyPictureBloc($data, $img, $imgAlt, $imgTitle, $width, $height);
$data = self::emptyPictureLinkBloc($data, $url);
$data = self::emptyButtonBooleanBloc($data, 'On Embauche');
return $data;
}
/**
* Get MiniCrud bloc for home_life section.
*
* @param array $data
* @return array
*/
public static function getHomeLifeBloc(array $data): array
{
return self::emptyButtonBooleanBloc($data, 'On Embauche');
}
/**
* Get MiniCrud bloc for unveil_pole section.
*
* @param array $data
* @param integer $keyValueSites
* @param integer $keyValueSpecies
* @param integer $keyValueCa
* @param integer $keyValueEmployees
* @return array
*/
public static function getUnveilPoleBloc(
array $data,
int $keyValueSites,
int $keyValueSpecies,
int $keyValueCa,
int $keyValueEmployees
): array {
$data = self::emptyKeyNumberBloc($data, 'sites', $keyValueSites);
$data = self::emptyKeyNumberBloc($data, 'espèces', $keyValueSpecies);
$data = self::emptyKeyNumberBloc($data, 'ca', $keyValueCa);
$data = self::emptyKeyNumberBloc($data, 'collaborateurs', $keyValueEmployees);
return $data;
}
/**
* Get MiniCrud bloc for hire_grow section.
*
* @param array $data
* @param string $title
* @return array
*/
public static function getHireGrowBloc(array $data, string $title): array
{
return self::emptyStringBloc(
$data,
sprintf("Titre h3 de la section %s", PageSectionEnum::hire_grow->label()),
$title
);
}
/**
* Get MiniCrud bloc for hire_parity section.
*
* @param array $data
* @param string $img
* @param string $imgAlt
* @param string $imgTitle
* @param integer $width
* @param integer $height
* @return array
*/
public static function getHireParityBloc(
array $data,
string $img,
string $imgAlt,
string $imgTitle,
int $width,
int $height
): array {
$data = self::emptyButtonBooleanBloc($data, 'On Bouge Ensemble');
$data = self::emptyPictureBloc($data, $img, $imgAlt, $imgTitle, $width, $height, true);
return $data;
}
/**
* Get MiniCrud bloc for commit_breeding section.
*
* @param array $data
* @param string $content
* @param string $string
* @return array
*/
public static function getCommitBreedingBloc(
array $data,
string $content,
string $string
): array {
$data = self::emptyWysiwygBloc($data, 'images', $content, \App\Enums\CkEditorConfigName::advanced);
$data = self::emptyButtonBooleanBloc($data, 'On Témoigne - engagements');
$data = self::emptyKeyNumberBloc($data, 'nombre');
$data = self::emptyWysiwygBloc($data, "text accompagnant le nombre", $string);
return $data;
}
/**
* Get MiniCrud bloc for commit_living section.
*
* @param array $data
* @param string $content
* @param string $string
* @return array
*/
public static function getCommitLivingBloc(array $data, string $content, string $string): array
{
$data = self::emptyButtonBooleanBloc($data, 'On Témoigne - engagements');
$data = self::emptyWysiwygBloc($data, 'numéro 2', $content, \App\Enums\CkEditorConfigName::advanced);
$data = self::emptyButtonBooleanBloc($data, 'On Bouge');
$data = self::emptyKeyNumberBloc($data, 'nombre n°1');
$data = self::emptyWysiwygBloc($data, "text accompagnant le nombre n°1", $string);
$data = self::emptyKeyNumberBloc($data, 'nombre n°2');
$data = self::emptyWysiwygBloc($data, "text accompagnant le nombre n°2", $string);
return $data;
}
/**
* Get MiniCrud bloc for commit_respect_earth section.
*
* @param array $data
* @param string $content
* @param string $img
* @param string $imgAlt
* @param string $imgTitle
* @param integer $width
* @param integer $height
* @return array
*/
public static function getCommitRespectEarthBloc(
array $data,
string $content,
string $img,
string $imgAlt,
string $imgTitle,
int $width,
int $height
): array {
$data = self::emptyKeyNumberBloc($data, 'nombre n°1');
$data = self::emptyWysiwygBloc($data, "text accompagnant le nombre n°1", $content);
$data = self::emptyKeyNumberBloc($data, 'nombre n°2');
$data = self::emptyWysiwygBloc($data, "text accompagnant le nombre n°2", $content);
$data = self::emptyButtonBooleanBloc($data, 'On Témoigne - engagements');
$data = self::emptyPictureBloc($data, $img, $imgAlt, $imgTitle, $width, $height);
$data = self::emptyWysiwygBloc($data, 'numéro 2', $content, \App\Enums\CkEditorConfigName::advanced);
return $data;
}
/**
* Get MiniCrud bloc for commit_feed section.
*
* @param array $data
* @param string $content
* @param string $secondContent
* @return array
*/
public static function getCommitFeedBloc(array $data, string $content, string $secondContent): array
{
$data = self::emptyKeyNumberBloc($data, 'nombre n°1');
$data = self::emptyWysiwygBloc($data, "text accompagnant le nombre n°1", $content);
$data = self::emptyKeyNumberBloc($data, 'nombre n°2');
$data = self::emptyWysiwygBloc($data, "text accompagnant le nombre n°2", $content);
$data = self::emptyButtonBooleanBloc($data, 'On Témoigne - engagements');
$data = self::emptyWysiwygBloc($data, 'numéro 2', $content, \App\Enums\CkEditorConfigName::advanced);
$data = self::emptyButtonBooleanBloc($data, 'On Produit');
$data = self::emptyWysiwygBloc($data, 'numéro 3', $secondContent, \App\Enums\CkEditorConfigName::advanced);
return $data;
}
/**
* Get MiniCrud bloc for commit_commitments section.
*
* @param array $data
* @param string $firstTitle
* @param string $secondTitle
* @return array
*/
public static function getCommitCommitmentsBloc(array $data, string $firstTitle, string $secondTitle): array
{
$data = self::emptyStringBloc($data, "Titre h3 de la section numéro 1", $firstTitle);
$data = self::emptyStringBloc($data, "Titre h3 de la section numéro 2", $secondTitle);
return $data;
}
/**
* Get MiniCrud bloc for move_commitments section.
*
* @param array $data
* @return array
*/
public static function getMoveCommitmentsBloc(array $data): array
{
return self::emptyButtonBooleanBloc($data, 'On Témoigne - engagements');
}
/**
* Get MiniCrud bloc for produce_linking section.
*
* @param array $data
* @param string $content
* @param string $secondContent
* @return array
*/
public static function getProduceLinkingBloc(array $data, string $content, string $secondContent): array
{
$data = self::emptyWysiwygBloc($data, 'numéro 2', $content);
$data = self::emptyButtonBooleanBloc($data, 'On vous écoute');
$data = self::emptyWysiwygBloc($data, 'numéro 3', $secondContent);
$data = self::emptyButtonBooleanBloc($data, 'On se Dévoile');
return $data;
}
// * METHODS.
/**
* Empty bloc for picture.
*
* @param array $data
* @param string $img
* @param string $imgAlt
* @param string $imgTitle
* @param integer $width
* @param integer $height
* @param boolean $required
* @return array
* @param array<string, mixed> $data
* @param string $img
* @param string $imgAlt
* @param string $imgTitle
* @param integer $width
* @param integer $height
* @param boolean $required
* @param string $name
* @return array<string, mixed>
*/
private static function emptyPictureBloc(
public static function emptyPictureBloc(
array $data,
string $img = '',
string $imgAlt = '',
@ -394,9 +111,10 @@ class Section extends Model
int $width = 100,
int $height = 100,
bool $required = false,
) {
$data["bloc_image"] = [
'label' => "Image",
string $name = 'image',
): array {
$data[sprintf('bloc_%s', Str::of($name)->snake()->ascii()->remove(['\'', '-']))] = [
'label' => $name,
'dimensions' => ['width' => $width, 'height' => $height],
'inputType' => InputType::image->value,
'alt' => $imgAlt,
@ -405,138 +123,163 @@ class Section extends Model
'validate' => $required ? 'required' : 'nullable',
'required' => $required
];
return $data;
}
/**
* Empty bloc for link associated to the picture.
* Empty bloc for link.
*
* @param array $data
* @param string $url
* @param boolean $required
* @return array
* @param array<string, mixed> $data
* @param string $url
* @param boolean $required
* @param string $name
* @return array<string, mixed>
*/
private static function emptyPictureLinkBloc(
public static function emptyLinkBloc(
array $data,
string $url = '',
bool $required = false,
) {
$data["bloc_image_link"] = [
'label' => "URL à ouvrir",
string $name = "URL à ouvrir",
): array {
$data[sprintf('bloc_%s', Str::of($name)->snake()->ascii()->remove(['\'', '-']))] = [
'label' => $name,
'inputType' => InputType::url->value,
'value' => $url,
'validate' => 'url|' . ($required ? 'required' : 'nullable'),
'required' => $required
];
return $data;
}
$data["bloc_image_link_new_tab"] = [
'label' => "Ouvrir dans un nouvel onglet",
/**
* Empty bloc for boolean new tab link.
*
* @param array<string, mixed> $data
* @param string $name
* @return array<string, mixed>
*/
public static function emptyLinkNewTabBloc(
array $data,
string $name = 'le lien',
): array {
$data["bloc_link_new_tab"] = [
'label' => "Ouvrir dans un nouvel onglet {$name}",
'inputType' => InputType::boolean->value,
'value' => true,
];
return $data;
}
/**
* Empty bloc for key numbers.
*
* @param array $data
* @param string $name
* @param integer $value
* @param boolean $required
*
* @return array
* @param array<string, mixed> $data
* @param string $name
* @param integer $value
* @param boolean $required
* @return array<string, mixed>
*/
private static function emptyKeyNumberBloc(
public static function emptyKeyNumberBloc(
array $data,
string $name,
int $value = 0,
bool $required = false,
) {
$snakeCaseName = Str::of($name)->snake()->ascii()->remove(['\'', '-']);
$data['bloc_key_' . $snakeCaseName] = [
): array {
$data['bloc_key_' . Str::of($name)->snake()->ascii()->remove(['\'', '-'])] = [
'label' => "Chiffre clé {$name}",
'inputType' => InputType::number->value,
'value' => $value,
'validate' => $required ? 'required' : 'nullable',
'required' => $required
];
return $data;
}
/**
* Empty bloc for the button boolean.
*
* @param array $data
* @param string $name
* @return array
* @param array<string, mixed> $data
* @param string $name
* @param boolean $value
* @return array<string, mixed>
*/
private static function emptyButtonBooleanBloc(
public static function emptyButtonBooleanBloc(
array $data,
string $name
) {
$snakeCaseName = Str::of($name)->snake()->ascii()->remove(['\'', '-']);
$data["bloc_button_{$snakeCaseName}"] = [
'label' => "Afficher le bouton {$name} ?",
string $name,
bool $value = false
): array {
$data['bloc_button_' . Str::of($name)->snake()->ascii()->remove(['\'', '-'])] = [
'label' => "Afficher le bouton '{$name}' ?",
'inputType' => InputType::boolean->value,
'value' => false
'value' => $value
];
return $data;
}
/**
* Empty bloc for a boolean.
*
* @param array<string, mixed> $data
* @param string $name
* @param boolean $value
* @return array<string, mixed>
*/
public static function emptyBooleanBloc(
array $data,
string $name,
bool $value = false
): array {
$data['bloc_boolean_' . Str::of($name)->snake()->ascii()->remove(['\'', '-'])] = [
'label' => "{$name} ?",
'inputType' => InputType::boolean->value,
'value' => $value
];
return $data;
}
/**
* Empty bloc for the h3 title.
*
* @param array $data
* @param string $name
* @param string $value
* @param boolean $required
* @return array
* @param array<string, mixed> $data
* @param string $name
* @param string $value
* @param boolean $required
* @return array<string, mixed>
*/
private static function emptyStringBloc(
public static function emptyStringBloc(
array $data,
string $name,
string $value = '',
bool $required = false
) {
$snakeCaseName = Str::of($name)->snake()->ascii()->remove(['\'', '-']);
$data["bloc_string_{$snakeCaseName}"] = [
): array {
$data['bloc_string_' . Str::of($name)->snake()->ascii()->remove(['\'', '-'])] = [
'label' => $name,
'inputType' => InputType::string->value,
'validate' => 'max:255|' . ($required ? 'required' : 'nullable'),
'value' => $value,
'required' => $required
];
return $data;
}
/**
* Empty bloc for the WYSIWYG content.
*
* @param array $data
* @param array<string, mixed> $data
* @param string $name
* @param string $value
* @param \App\Enums\CkEditorConfigName $config
* @param boolean $required
* @return array
* @return array<string, mixed>
*/
private static function emptyWysiwygBloc(
public static function emptyWysiwygBloc(
array $data,
string $name,
string $value = '',
\App\Enums\CkEditorConfigName $config = \App\Enums\CkEditorConfigName::base,
CkEditorConfigName $config = CkEditorConfigName::basic,
bool $required = false
) {
$snakeCaseName = Str::of($name)->snake()->ascii()->remove(['\'', '-']);
$data["bloc_{$snakeCaseName}_content"] = [
): array {
$data['bloc_' . Str::of($name)->snake()->ascii()->remove(['\'', '-']) . '_content'] = [
'label' => "Contenu de la section {$name}",
'inputType' => InputType::text->value,
'validate' => $required ? 'required' : 'nullable',
@ -544,19 +287,224 @@ class Section extends Model
'required' => $required,
'config' => $config->name
];
return $data;
}
// * RELATIONS
/**
* Add part piece.
*
* @return void
*/
public function addPartPiece(): void
{
$pieceTemplateLinesCount = self::countPartPieces();
$pieceToAdd = self::getAddablePartPieceBlock(
$this->section,
$this->countPartPieces() + 1
);
/** @var array<string, mixed> $rawData */
$rawData = $this->data;
$data = collect($rawData);
$linesToSkip = 1;
$groupedPieces = $data->skip($linesToSkip)->splitIn($data->count() / ($pieceTemplateLinesCount ?: 1))
->concat([$pieceToAdd])
->sort(function ($aCollect, $bCollect) {
if ($this->section->equals(PageSectionEnum::produce_rhd)) {
/** @var array<string, mixed> $aFirst */
$aFirst = collect($aCollect)->first();
/** @var array<string, mixed> $bFirst */
$bFirst = collect($bCollect)->first();
return strcmp(
strrev((string) collect($aFirst)->first()),
strrev((string) collect($bFirst)->first())
);
}
return 0;
});
$groupedPieces->prepend([$data->keys()->first() => $data->first()]);
$this->data = $groupedPieces->collapse()->all();
}
/**
* Remove part piece.
*
* @param integer $index
* @return integer Elements count removed.
*/
public function removePartPiece(int $index): int
{
$pieceTemplate = self::getPartPieces();
$pieceTemplateLinesCount = self::countPartPieces();
if (!$pieceTemplateLinesCount) {
return 0;
}
$linesToSkip = 1;
$data = collect($this->data);
$groupedPieces = $data->skip($linesToSkip)->splitIn($data->count() / count($pieceTemplate));
$removedGroup = $groupedPieces->splice($index - 1, 1);
$this->data = $groupedPieces->collapse()
->prepend($data->first(), $data->keys()->first())
->all();
return $removedGroup->count();
}
/**
* Count part pieces.
*
* @return integer
*/
public function countPartPieces(): int
{
$pieceTemplate = self::getPartPieces();
$data = collect($this->data);
$templateKeys = collect($pieceTemplate)->keys();
$dataCount = $data->count();
$repetitionCount = 0;
for ($i = 1; $i <= $dataCount; $i++) {
$indexKeys = $templateKeys->map(fn($key) => str_replace('__index', strval($i), $key));
if ($indexKeys->every(fn($key) => $data->has($key))) {
$repetitionCount++;
}
}
return $repetitionCount;
}
/**
* Get part pieces.
*
* @return array<string, mixed>
*/
private function getPartPieces(): array
{
$pieceTemplate = self::getAddablePartPieceBlockTemplate($this->section);
return is_null($pieceTemplate) ? [] : $pieceTemplate;
}
/**
* Addable part piece block.
*
* @param \App\Enums\Sections\PageSectionEnum $sectionEnum
* @param integer $index
* @return array<string, mixed>|null
*/
public static function getAddablePartPieceBlock(PageSectionEnum $sectionEnum, int $index = 1): array|null
{
$data = null;
$pieceTemplate = self::getAddablePartPieceBlockTemplate($sectionEnum);
if (!is_null($pieceTemplate)) {
$encoded = json_encode($pieceTemplate);
if ($encoded !== false) {
/** @var array<string, mixed> $data */
$data = json_decode(Str::of($encoded)->replace('__index', strval($index)), true);
}
}
return $data;
}
/**
* Addable part piece block.
*
* @param \App\Enums\Sections\PageSectionEnum $sectionEnum
* @return array<int, string>|null
*/
public static function getAddablePartPieceBlockIndexes(PageSectionEnum $sectionEnum): array|null
{
$data = self::getAddablePartPieceBlockTemplate($sectionEnum);
if (!is_null($data)) {
return array_keys($data);
}
return $data;
}
/**
* Addable part piece block template.
*
* @param \App\Enums\Sections\PageSectionEnum $sectionEnum
* @return array<string, mixed>|null
*/
private static function getAddablePartPieceBlockTemplate(PageSectionEnum $sectionEnum): array|null
{
$data = null;
switch ($sectionEnum) {
case PageSectionEnum::produce_export:
$data = array_merge(
self::emptyWysiwygBloc(
[],
"accompagnant l'image __index de la partie",
''
),
self::emptyPictureBloc([], '', '', '', 100, 100, true, "Image __index de la partie"),
self::emptyLinkBloc([], '', false, "Lien de l'image__index de la partie")
);
break;
case PageSectionEnum::produce_rhd:
$data = array_merge(
self::emptyWysiwygBloc(
[],
"accompagnant l'image __index de la partie 1",
''
),
self::emptyPictureBloc([], '', '', '', 100, 100, true, "Image __index de la partie 1"),
self::emptyLinkBloc([], '', false, "Lien de l'image__index de la partie 1")
);
break;
default:
} //end switch
return $data;
}
/**
* Returns the list of sections for a page type.
*
* @param \App\Enums\StaticPageType $type
* @return \Illuminate\Database\Eloquent\Collection<int, self>
*/
public static function getSections(StaticPageType $type): \Illuminate\Database\Eloquent\Collection
{
$staticPageModel = StaticPage::query()->where('type', $type)->first();
$sectionModels = self::where('page_id', $staticPageModel->id)->get();
return $sectionModels;
}
/**
* Get the active section for a type page.
*
* @param \App\Enums\StaticPageType $type
* @return boolean
*/
public static function isActive(StaticPageType $type)
{
$staticPage = StaticPage::getStaticPage($type);
return $staticPage->sections->contains(
function ($section) {
return request()->is("bo/sections/$section->id/edit");
}
);
}
// * RELATIONS.
/**
* Get the page that owns the section.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\StaticPage,$this>
*/
public function page(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(StaticPage::class);
}
/**
* Get the sections that own the carousel.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\Carousel,$this>
*/
public function carousels(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Carousel::class);
}
}

Some files were not shown because too many files have changed in this diff Show more