aboutsummaryrefslogtreecommitdiff
path: root/src/controller
diff options
context:
space:
mode:
Diffstat (limited to 'src/controller')
-rw-r--r--src/controller/ArticleController.php239
-rw-r--r--src/controller/CalendarController.php74
-rw-r--r--src/controller/ContactFormController.php102
-rw-r--r--src/controller/FileUploadController.php65
-rw-r--r--src/controller/HeadFootController.php141
-rw-r--r--src/controller/ImageUploadController.php191
-rw-r--r--src/controller/MaintenanceController.php147
-rw-r--r--src/controller/MenuAndPathsController.php219
-rw-r--r--src/controller/PageManagementController.php362
-rw-r--r--src/controller/UserController.php230
-rw-r--r--src/controller/ViewController.php63
11 files changed, 0 insertions, 1833 deletions
diff --git a/src/controller/ArticleController.php b/src/controller/ArticleController.php
deleted file mode 100644
index 0ddb0e1..0000000
--- a/src/controller/ArticleController.php
+++ /dev/null
@@ -1,239 +0,0 @@
1<?php
2// src/controller/ArticleController.php
3
4declare(strict_types=1);
5
6use App\Entity\Node;
7use App\Entity\Article;
8use App\Entity\Presentation;
9use Doctrine\ORM\EntityManager;
10use Symfony\Component\HttpFoundation\Request;
11use Symfony\Component\HttpFoundation\Response;
12use Symfony\Component\HttpFoundation\JsonResponse;
13use Symfony\Component\HttpFoundation\RedirectResponse;
14
15class ArticleController
16{
17 static public function fetch(EntityManager $entityManager, Request $request): JsonResponse
18 {
19 if($request->query->has('id') && !empty($request->query->get('id')) && $request->query->has('last_article')){
20 $id = (int)$request->get('id'); // type et nettoie
21 $model = new Model($entityManager);
22 $model->findNodeById($id);
23 $parent_block = $model->getNode();
24
25 if(Presentation::hasPresentation($parent_block->getName())){
26 $get_articles_return = $model->getNextArticles($parent_block, $request);
27 $bulk_data = $get_articles_return[0];
28
29 if($parent_block->getName() === 'post_block'){
30 $builder_name = 'PostBuilder';
31 }
32 elseif($parent_block->getName() === 'news_block'){
33 $builder_name = 'NewBuilder';
34 }
35 else{
36 return new JsonResponse(['success' => false, 'error' => 'server side error'], JsonResponse::HTTP_INTERNAL_SERVER_ERROR);
37 }
38
39 $html = '';
40 foreach($bulk_data as $article){
41 $builder = new $builder_name($article);
42 $html .= $builder->render();
43 }
44
45 return new JsonResponse(['success' => true, 'html' => $html, 'truncated' => $get_articles_return[1]]);
46 }
47 else{
48 return new JsonResponse(['success' => false, 'error' => 'server side error'], JsonResponse::HTTP_INTERNAL_SERVER_ERROR);
49 }
50 }
51 else{
52 return new JsonResponse(['success' => false, 'error' => 'bad parameters'], JsonResponse::HTTP_BAD_REQUEST);
53 }
54 }
55
56 static public function editorSubmit(EntityManager $entityManager, array $json): JsonResponse
57 {
58 if(json_last_error() === JSON_ERROR_NONE){
59 $id = $json['id'];
60 if(in_array($id[0], ['t', 'p', 'i', 'd'])){
61 $id = substr($id, 1);
62 }
63
64 $model = new Model($entityManager);
65 $content = $json['content'];
66
67 // nettoyage
68 if(is_array($content)){ // cas d'une nouvelle "news"
69 foreach($content as $one_input){
70 $one_input = Security::secureHTML($one_input);
71 }
72 }
73 else{ // autres cas
74 $content = Security::secureHTML($json['content']);
75 }
76
77 // nouvel article
78 if($json['id'][0] === 'n'){ // ici $id est un bloc
79 $section_id = (int)substr($id, 1); // id du bloc <section>
80 if(!$model->findNodeById($section_id)){ // erreur mauvais id
81 return new JsonResponse(['success' => false, 'error' => 'article_not_saved, bad id']);
82 }
83 $model->makeSectionNode();
84 $section = $model->getNode();
85
86 // ajout d'une news
87 if(is_array($content)){
88 if($section->getPage()->getEndOfPath() !== $json['from']){ // erreur mauvais from
89 return new JsonResponse(['success' => false, 'error' => 'article_not_saved, bad from']);
90 }
91
92 $date = new \DateTime($content['d'] . ':' . (new \DateTime)->format('s')); // l'input type="datetime-local" ne donne pas les secondes, on les ajoute: 'hh:mm' . ':ss'
93 $article = new Article($content['i'], $date, $content['t'], $content['p']);
94 $article_node = new Node('new', count($section->getChildren()) + 1, $section, $section->getPage(), $article);
95 }
96 // ajout d'un post
97 else{
98 $timestamp = time();
99 $date = new \DateTime;
100 $date->setTimestamp($timestamp);
101
102 $article = new Article($content, $date);
103 $placement = $json['placement'] === 'first' ? 0 : count($section->getChildren()) + 1; //
104 $article_node = new Node('post', $placement, $section, $section->getPage(), $article);
105
106 if($json['placement'] === 'first'){
107 $section->addChild($article_node);
108 $section->sortChildren(true); // mettre $article_node au début du tableau puis régénérer les positions (0 devient 1, 1 devient 2...)
109 }
110 }
111
112 $entityManager->persist($article_node);
113 $entityManager->flush();
114
115 return new JsonResponse(['success' => true, 'article_id' => $article_node->getId()]);
116 }
117 // modification article
118 //else{}
119
120 if($model->makeArticleNode($id)){ // une entrée est trouvée
121 $node = $model->getArticleNode();
122 switch($json['id'][0]){
123 case 'i':
124 $node->getArticle()->setContent($content);
125 break;
126 case 'p':
127 $node->getArticle()->setPreview($content); // html de l'éditeur
128 break;
129 case 't':
130 $node->getArticle()->setTitle($content); // html de l'éditeur
131 break;
132 case 'd':
133 return new JsonResponse(['success' => false, 'message' => 'l\'action editor_submit ne supporte pas les dates, utiliser date_submit.']);
134 default: // modif article simple (id sans lettre devant)
135 $node->getArticle()->setContent($content);
136 }
137 $entityManager->flush();
138 return new JsonResponse(['success' => true]);
139 }
140 else{
141 return new JsonResponse(['success' => false, 'message' => 'article non identifié']);
142 }
143 }
144 else{
145 return new JsonResponse(['success' => false, 'message' => 'Erreur de décodage JSON']);
146 }
147 }
148
149 static public function deleteArticle(EntityManager $entityManager, Request $request): Response
150 {
151 $model = new Model($entityManager);
152
153 if($request->headers->get('Content-Type') === 'application/json'){
154 $id = json_decode($request->getContent(), true)['id'];
155 }
156 elseif($request->headers->get('Content-Type') === 'application/x-www-form-urlencoded'){
157 $id = $request->query->get('id');
158 }
159 // ni JSON ni form, c'est quoi? un POST vide?
160 else{
161 return new Response('la méthode deleteArticle ne peut être appelée de cette manière');
162 }
163
164 if(!$model->makeArticleNode($id, true)){
165 $params = ['false', "Erreur 500 pas d\'article à supprimer"];
166 }
167 else{
168 $article = $model->getArticleNode();
169 $section = $model->getNode();
170
171 $entityManager->remove($article);
172 $section->removeChild($article);
173 $section->sortChildren(true); // régénère les positions
174
175 try{
176 $entityManager->flush();
177 $params = ['true', 'Article supprimé avec succès'];
178 }
179 catch(Exception $e){
180 $params = ['false', 'Erreur 500 ' . $e->getMessage()];
181 }
182 }
183
184 if($request->headers->get('Content-Type') === 'application/json'){
185 return new JsonResponse(
186 ['success' => $params[0], 'message' => $params[1]],
187 $params[0] ? JsonResponse::HTTP_OK : JsonResponse::HTTP_INTERNAL_SERVER_ERROR
188 );
189 }
190 elseif($request->headers->get('Content-Type') === 'application/x-www-form-urlencoded'){
191 $url = new URL(['page' => $request->query->get('from') ?? '', 'success' => $params[0], 'message' => $params[1]]);
192 return new RedirectResponse((string)$url);
193 }
194 else{
195 // cas inaccesible
196 throw new Exception('la méthode deleteArticle ne peut être appelée de cette manière');
197 }
198 }
199
200 static public function switchPositions(EntityManager $entityManager, array $json): JsonResponse
201 {
202 $model = new Model($entityManager);
203 $model->makeArticleNode($json['id1'], true);
204 $article1 = $model->getArticleNode();
205 $section = $model->getNode();
206
207 $section->sortChildren(true); // régénère les positions avant inversion
208 $article2 = null;
209 foreach($section->getChildren() as $child){
210 if((string)$child->getId() === $json['id2']) // type string
211 {
212 $article2 = $child;
213 break;
214 }
215 }
216
217 // inversion
218 $tmp = $article1->getPosition();
219 $article1->setPosition($article2->getPosition());
220 $article2->setPosition($tmp);
221 $entityManager->flush();
222
223 return new JsonResponse(['success' => true]);
224 }
225
226 static public function dateSubmit(EntityManager $entityManager, array $json): JsonResponse
227 {
228 $id = substr($json['id'], 1);
229 $date = new DateTime($json['date']);
230
231 $model = new Model($entityManager);
232 $model->makeArticleNode($id);
233 $node = $model->getArticleNode();
234 $node->getArticle()->setDateTime($date);
235 $entityManager->flush();
236
237 return new JsonResponse(['success' => true]);
238 }
239} \ No newline at end of file
diff --git a/src/controller/CalendarController.php b/src/controller/CalendarController.php
deleted file mode 100644
index 1a62afa..0000000
--- a/src/controller/CalendarController.php
+++ /dev/null
@@ -1,74 +0,0 @@
1<?php
2// /src/controller/CalendarController.php
3
4declare(strict_types=1);
5
6use Doctrine\ORM\EntityManager;
7use App\Entity\Event;
8use Symfony\Component\HttpFoundation\JsonResponse;
9
10class CalendarController
11{
12 static public function getData(EntityManager $entityManager): JsonResponse
13 {
14 // bornes début et fin du calendrier affiché à l'heure locale
15 // noter que la vue "planning" est similaire à la vue "semaine"
16 $start = new DateTime($_GET['start']);
17 $end = new DateTime($_GET['end']);
18 $start->setTimezone(new DateTimeZone('UTC'));
19 $end->setTimezone(new DateTimeZone('UTC'));
20
21 // affichage format ISO à l'heure UTC
22 //$date->format('Y-m-d\TH:i:s\Z');
23
24 // on prend les évènements se finissant après le début ou commençant avant la fin de la fourchette
25 $dql = 'SELECT e FROM App\Entity\Event e WHERE e.end >= :start AND e.start <= :end';
26 $bulk_data = $entityManager->createQuery($dql)
27 ->setParameter('start', $start)
28 ->setParameter('end', $end)
29 ->getResult();
30
31 $events = [];
32 foreach($bulk_data as $one_entry){
33 $event = new EventDTO($one_entry);
34 $events[] = $event->toArray();
35 }
36
37 return new JsonResponse($events);
38 }
39
40 static public function newEvent(array $json, EntityManager $entityManager): JsonResponse
41 {
42 try{
43 $event = new Event($json);
44 }
45 catch(InvalidArgumentException $e){
46 return new JsonResponse(['success' => false, 'error' => $e->getMessage()], JsonResponse::HTTP_BAD_REQUEST); // code 400
47 }
48 $entityManager->persist($event);
49 $entityManager->flush();
50
51 return new JsonResponse(['success' => true, 'id' => $event->getId()]);
52 }
53 static public function updateEvent(array $json, EntityManager $entityManager): JsonResponse
54 {
55 $event = $entityManager->find('App\Entity\Event', (int)$json['id']);
56 try{
57 $event->securedUpdateFromJSON($json);
58 }
59 catch(InvalidArgumentException $e){
60 return new JsonResponse(['success' => false, 'error' => $e->getMessage()], JsonResponse::HTTP_BAD_REQUEST); // code 400
61 }
62 $entityManager->flush();
63
64 return new JsonResponse(['success' => true]);
65 }
66 static public function removeEvent(array $json, EntityManager $entityManager): JsonResponse
67 {
68 $event = $entityManager->find('App\Entity\Event', (int)$json['id']);
69 $entityManager->remove($event);
70 $entityManager->flush();
71
72 return new JsonResponse(['success' => true]);
73 }
74} \ No newline at end of file
diff --git a/src/controller/ContactFormController.php b/src/controller/ContactFormController.php
deleted file mode 100644
index 82e9b17..0000000
--- a/src/controller/ContactFormController.php
+++ /dev/null
@@ -1,102 +0,0 @@
1<?php
2// src/controller/ContactFormController.php
3
4declare(strict_types=1);
5
6use Doctrine\ORM\EntityManager;
7use App\Entity\EmailForm;
8use App\Entity\Email;
9use Symfony\Component\HttpFoundation\JsonResponse;
10
11class ContactFormController
12{
13 static public function keepEmails(EntityManager $entityManager, array $json): JsonResponse
14 {
15 $form_data = $entityManager->find(EmailForm::class, $json['id']);
16 $form_data->updateData('keep_emails', $json['checked'] ? true : false);
17 $entityManager->persist($form_data);
18 $entityManager->flush();
19 return new JsonResponse(['success' => true, 'checked' => $json['checked']]);
20 }
21 static public function setEmailsRetentionPeriod(EntityManager $entityManager, array $json): JsonResponse
22 {
23 $form_data = $entityManager->find(EmailForm::class, $json['id']);
24 $form_data->updateData($json['field'], (int)$json['months']);
25 $entityManager->persist($form_data);
26 $entityManager->flush();
27 return new JsonResponse(['success' => true, 'months' => $json['months']]);
28 }
29 static public function setEmailParam(EntityManager $entityManager, array $json): JsonResponse
30 {
31 $form = new FormValidation($json, ValidationStrategy::EmailParam);
32
33 if($form->validate()){
34 $form_data = $entityManager->find(EmailForm::class, $json['id']);
35 $form_data->updateData($json['what_param'], trim($json['value']));
36 $entityManager->persist($form_data); // ??
37 $entityManager->flush();
38 return new JsonResponse(['success' => true]);
39 }
40 else{
41 return new JsonResponse(['success' => false, 'error' => $form->getError()]);
42 }
43 }
44
45 // les deux méthodes suivantes sont "factorisables", elles ne se distinguent que par la gestion ou non du formulaire rempli par le visiteur
46 static public function sendVisitorEmail(EntityManager $entityManager, array $json): JsonResponse
47 {
48 $form = new FormValidation($json, ValidationStrategy::EmailSend);
49
50 $error = '';
51 if($form->validate()){
52 // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur
53 $form_data = $entityManager->find(EmailForm::class, $json['id']);
54 if($form_data === null){
55 return new JsonResponse(['success' => false, 'error' => 'server_error'], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
56 }
57
58 if(!EmailService::send($entityManager, $form_data, false, $form->getField('name'), $form->getField('email'), $form->getField('message'))){
59 $error = 'email_not_sent';
60 }
61 }
62 else{
63 $error = $form->getError();
64 }
65
66 if(empty($error)){
67 return new JsonResponse(['success' => true]);
68 }
69 else{
70 return new JsonResponse(['success' => false, 'error' => $error]);
71 }
72 }
73 static public function sendTestEmail(EntityManager $entityManager, array $json): JsonResponse
74 {
75 // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur
76 $form_data = $entityManager->find(EmailForm::class, $json['id']);
77 if($form_data === null){
78 return new JsonResponse(['success' => false, 'error' => 'server_error'], JsonResponse::HTTP_INTERNAL_SERVER_ERROR);
79 }
80
81 if(EmailService::send($entityManager, $form_data, true, 'nom du visiteur', 'adresse@du_visiteur.fr', "TEST d'un envoi d'e-mail depuis le site web")){
82 return new JsonResponse(['success' => true]);
83 }
84 else{
85 return new JsonResponse(['success' => false, 'error' => 'email_not_sent']);
86 }
87 }
88 static public function deleteEmail(EntityManager $entityManager, array $json): JsonResponse
89 {
90 $email = $entityManager->find(Email::class, $json['id']);
91 $entityManager->remove($email);
92 $entityManager->flush();
93 return new JsonResponse(['success' => true]);
94 }
95 static public function toggleSensitiveEmail(EntityManager $entityManager, array $json): JsonResponse
96 {
97 $email = $entityManager->find(Email::class, $json['id']);
98 $email->makeSensitive($json['checked']);
99 $entityManager->flush();
100 return new JsonResponse(['success' => true, 'checked' => $json['checked'], 'deletion_date' => $email->getDeletionDate()->format('d/m/Y')]);
101 }
102} \ No newline at end of file
diff --git a/src/controller/FileUploadController.php b/src/controller/FileUploadController.php
deleted file mode 100644
index 3cd5e6b..0000000
--- a/src/controller/FileUploadController.php
+++ /dev/null
@@ -1,65 +0,0 @@
1<?php
2// src/controller/FileUploadController.php
3
4declare(strict_types=1);
5
6use Symfony\Component\HttpFoundation\JsonResponse;
7
8class FileUploadController
9{
10 static private function checkFileDownload(array $file): bool
11 {
12 $extensions_white_list = ['pdf', 'rtf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp']; // = extensions_white_list côté javascript
13 $mime_type_white_list = ['application/pdf', 'application/rtf', 'text/rtf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation'];
14
15 // 1/ extension
16 $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
17 if(!in_array($extension, $extensions_white_list, true)){
18 return false;
19 }
20
21 // 2/ fichier obtenu par HTTP POST (théoriquement inutile si le routeur est solide, mais ça ne mange pas de pain)
22 if(!is_uploaded_file($file['tmp_name'])){
23 return false;
24 }
25
26 // 3/ objet $finfo valide (dépend du paramètre FILEINFO_MIME_TYPE)
27 $finfo = new finfo(FILEINFO_MIME_TYPE);
28 if($finfo === false){
29 return false;
30 }
31
32 // 4/ contrôle du "vrai" type mime (finfo_file lit les 1ers octets des fichiers pour y trouver des "signatures", très fiable sauf avec les conteneurs: doc, zip...)
33 $real_type = finfo_file($finfo, $file['tmp_name']);
34 return in_array($real_type, $mime_type_white_list, true);
35 }
36
37 static public function fileUploadTinyMce(): JsonResponse
38 {
39 if(isset($_FILES['file'])){
40 $dest = 'user_data/media/';
41 if(!is_dir($dest)){ // Vérifier si le répertoire existe, sinon le créer
42 mkdir($dest, 0755, true);
43 }
44
45 $name = Security::secureFileName(pathinfo($_FILES['file']['name'], PATHINFO_FILENAME)); // retirer caractères spéciaux et changer espaces en underscores
46 $extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
47 $file_path = $dest . $name . '_' . uniqid() . '.' . $extension; // nom unique
48
49 if(self::checkFileDownload($_FILES['file'])){
50 if(move_uploaded_file($_FILES['file']['tmp_name'], $file_path)){
51 return new JsonResponse(['location' => $file_path]);
52 }
53 else{
54 return new JsonResponse(['message' => 'Erreur enregistrement du fichier.'], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
55 }
56 }
57 else{
58 return new JsonResponse(['message' => 'Erreur 400: fichier non valide.'], JsonResponse::HTTP_BAD_REQUEST); // code 400
59 }
60 }
61 else{
62 return new JsonResponse(['message' => 'Erreur 400: Bad Request'], JsonResponse::HTTP_BAD_REQUEST); // code 400
63 }
64 }
65} \ No newline at end of file
diff --git a/src/controller/HeadFootController.php b/src/controller/HeadFootController.php
deleted file mode 100644
index 72487d8..0000000
--- a/src/controller/HeadFootController.php
+++ /dev/null
@@ -1,141 +0,0 @@
1<?php
2// src/controller/HeadFootController.php
3
4declare(strict_types=1);
5
6use App\Entity\NodeData;
7use App\Entity\Asset;
8use App\Entity\AssetEmployment;
9use Doctrine\ORM\EntityManager;
10use Symfony\Component\HttpFoundation\JsonResponse;
11
12class HeadFootController
13{
14 static public function setTextData(EntityManager $entityManager, string $request_params, array $json): JsonResponse
15 {
16 $params_array = explode('_', $request_params); // header_title, header_description, footer_name, footer_address, footer_email
17 if(count($params_array) !== 2){
18 return new JsonResponse(['success' => false]);
19 }
20
21 $model = new Model($entityManager);
22 if($model->findWhateverNode('name_node', $params_array[0])){
23 $node_data = $model->getNode()->getNodeData();
24
25 // liens réseaux sociaux
26 if(in_array($params_array[1], NodeData::$social_networks)){
27 $social = $node_data->getData()['social'] ?? [];
28 $social[$params_array[1]] = $json['new_text'];
29 $node_data->updateData('social', $social);
30 }
31 // autres textes
32 else{
33 $node_data->updateData($params_array[1], $json['new_text']); // $params_array[1] n'est pas contrôlé
34 }
35
36 $entityManager->flush();
37 return new JsonResponse(['success' => true]);
38 }
39 else{
40 return new JsonResponse(['success' => false]);
41 }
42 }
43 static public function uploadAsset(EntityManager $entityManager, string $request_params): JsonResponse
44 {
45 if(empty($_FILES)){
46 return new JsonResponse(['success' => false], JsonResponse::HTTP_BAD_REQUEST); // code 400
47 }
48 else{
49 if(!is_dir(Asset::USER_PATH)){
50 mkdir(Asset::USER_PATH, 0777, true);
51 }
52
53 /* -- téléchargement -- */
54 $file = $_FILES['file'];
55 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif', 'ico', 'bmp']; // pas de SVG
56 $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
57 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
58 $extension = 'jpeg';
59 }
60 $mime_type = mime_content_type($file['tmp_name']);
61 $hash = hash_file('sha256', $file['tmp_name']);
62
63 /* -- instance d'Asset -- */
64 $model = new Model($entityManager);
65 $result = $model->getWhatever('App\Entity\Asset', 'hash', $hash);
66
67 if(count($result) > 0){ // asset existant trouvé
68 $asset = $result[0];
69
70 // correction des informations
71 $name = $asset->getFileName(); // permet à priori de réécrire par dessus le précédent fichier
72 //$asset->setFileName($name);
73 $asset->setMimeType($mime_type);
74 }
75 else{
76 $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME));
77 $name = uniqid($name . '_') . '.' . $extension;
78 $asset = new Asset($name, $mime_type, $hash);
79 }
80
81 /* -- écriture du fichier sur le disque -- */
82 if(!ImageUploadController::imagickCleanAndWriteImage(file_get_contents($file['tmp_name']), Asset::USER_PATH . $name)){ // recréer l’image pour la nettoyer
83 return new JsonResponse(['success' => false, 'message' => "Erreur de l'enregistrement de l'image: problème de permission ou format non valide.", 'format' => $extension], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
84 }
85 else{
86 $params_array = explode('_', $request_params); // head_favicon, header_logo, header_background, footer_logo
87
88 /* -- table intermédiaire node_data/asset-- */
89 if($model->findWhateverNode('name_node', $params_array[0])){ // noeud (head, header ou footer)
90 $node_data = $model->getNode()->getNodeData();
91
92 // recherche à l'aide du rôle
93 $old_nda = null;
94 foreach($node_data->getNodeDataAssets() as $nda){
95 if($nda->getRole() === $request_params){
96 $old_nda = $nda;
97 $old_nda->setAsset($asset);
98 break;
99 }
100 }
101 // entrée pas trouvée
102 if($old_nda === null){
103 $new_nda = new AssetEmployment($node_data, $asset, $request_params); // $request_params sera le rôle de l'asset
104 $entityManager->persist($new_nda);
105 }
106
107 if(count($result) === 0){
108 $entityManager->persist($asset);
109 }
110 $entityManager->flush();
111 return new JsonResponse(['success' => true, 'location' => Asset::USER_PATH . $name, 'mime_type' => $mime_type]);
112 }
113 else{
114 return new JsonResponse(['success' => false, 'message' => "Erreur noeud non trouvé, c'est pas du tout normal!"], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
115 }
116 }
117 }
118 }
119
120 static public function displaySocialNetwork(EntityManager $entityManager, string $request_params, array $json): JsonResponse
121 {
122 $params_array = explode('_', $request_params);
123 if(count($params_array) !== 2){
124 return new JsonResponse(['success' => false]);
125 }
126
127 $model = new Model($entityManager);
128 if(in_array($params_array[1], NodeData::$social_networks) && $model->findWhateverNode('name_node', $params_array[0])){
129 $node_data = $model->getNode()->getNodeData();
130 $social_show = $node_data->getData()['social_show'] ?? [];
131 $social_show[$params_array[1]] = $json['checked'];
132 $node_data->updateData('social_show', $social_show);
133
134 $entityManager->flush();
135 return new JsonResponse(['success' => true, 'checked' => $json['checked']]);
136 }
137 else{
138 return new JsonResponse(['success' => false]);
139 }
140 }
141} \ No newline at end of file
diff --git a/src/controller/ImageUploadController.php b/src/controller/ImageUploadController.php
deleted file mode 100644
index af9a553..0000000
--- a/src/controller/ImageUploadController.php
+++ /dev/null
@@ -1,191 +0,0 @@
1<?php
2// src/controller/ImageUploadController.php
3
4declare(strict_types=1);
5
6use Symfony\Component\HttpFoundation\JsonResponse;
7
8class ImageUploadController
9{
10 const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
11
12 static public function imagickCleanAndWriteImage(string $image_data, string $local_path): bool // "string" parce que file_get_contents...
13 {
14 $format = strtolower(pathinfo($local_path)['extension']);
15 try{
16 $imagick = new Imagick();
17 $imagick->readImageBlob($image_data);
18 $imagick->stripImage(); // nettoyage métadonnées
19 //$imagick->setImageFormat($format); // inutile, writeImage force la conversion
20
21 // compression
22 switch($format){
23 case 'jpeg': // particularité du switch, si 'jpeg' le test de 'jpg' est ignoré et on va jusqu'au break
24 case 'jpg':
25 $imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
26 $imagick->setImageCompressionQuality(85);
27 break;
28 case 'webp':
29 $imagick->setImageCompression(Imagick::COMPRESSION_WEBP);
30 $imagick->setImageCompressionQuality(85);
31 break;
32 case 'png':
33 $imagick->setImageCompression(Imagick::COMPRESSION_ZIP);
34 $imagick->setImageCompressionQuality(7); // 9 est sans perte
35 break;
36 case 'tiff':
37 $imagick->setImageCompression(Imagick::COMPRESSION_LZW); // LZW est sans perte
38 break;
39 }
40
41 // enregistrement
42 // writeImage utilise l'extension du fichier et ignore le format détecté
43 // imagemagick est à l'origine une appli console, elle considère que l'extension montre l'intention de l'utilisateur
44 $imagick->writeImage($local_path); // enregistrement
45 $imagick->clear();
46 $imagick->destroy();
47 return true;
48 }
49 catch(Exception $e){
50 return false;
51 }
52 }
53 static public function curlDownloadImage(string $url, int $maxRetries = 3, int $timeout = 10): string|false
54 {
55 $attempt = 0;
56 $imageData = false;
57
58 while($attempt < $maxRetries){
59 $ch = curl_init($url); // instance de CurlHandle
60 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
61 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
62 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
63 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
64 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
65 curl_setopt($ch, CURLOPT_USERAGENT, 'TinyMCE-Image-Downloader');
66
67 $imageData = curl_exec($ch);
68 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
69 //$curlError = curl_error($ch);
70
71 if($imageData !== false && $httpCode >= 200 && $httpCode < 300){
72 return $imageData;
73 }
74
75 $attempt++;
76 sleep(1);
77 }
78
79 return false; // échec après trois tentatives
80 }
81
82 // téléchargement par le plugin (bouton "insérer une image")
83 static public function imageUploadTinyMce(): JsonResponse
84 {
85 if(!isset($_FILES['file'])){
86 return new JsonResponse(['message' => 'Erreur 400: Bad Request'], JsonResponse::HTTP_BAD_REQUEST); // code 400
87 }
88 if(!is_uploaded_file($_FILES['file']['tmp_name'])) {
89 return new JsonResponse(['message' => "Le fichier n'a pas été téléchargé correctement."], JsonResponse::HTTP_BAD_REQUEST); // code 400
90 }
91
92 $dest = 'user_data/images/';
93 $dest_mini = 'user_data/images-mini/';
94
95 // Vérifier si les répertoires existent, sinon les créer
96 if(!is_dir($dest)){
97 mkdir($dest, 0755, true);
98 }
99 if(!is_dir($dest_mini)){
100 mkdir($dest_mini, 0755, true);
101 }
102
103 $name = Security::secureFileName(pathinfo($_FILES['file']['name'], PATHINFO_FILENAME));
104 $extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
105 $image_data = file_get_contents($_FILES['file']['tmp_name']);
106 if(!in_array($extension, self::ALLOWED_EXTENSIONS)){
107 $extension = 'jpeg';
108 }
109 $local_path = uniqid($dest . $name . '_') . '.' . $extension;
110
111 // créer une miniature de l'image
112 //
113
114 if(self::imagickCleanAndWriteImage($image_data, $local_path)){ // recréer l’image pour la nettoyer
115 return new JsonResponse(['location' => $local_path]); // renvoyer l'URL de l'image téléchargée
116 }
117 else{
118 return new JsonResponse(['message' => 'Erreur image non valide'], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
119 }
120 }
121
122 // collage de HTML => recherche de balises <img>, téléchargement côté serveur et renvoi de l'adresse sur le serveur
123 static public function uploadImageHtml(): JsonResponse
124 {
125 $json = json_decode(file_get_contents('php://input'), true);
126
127 if(!isset($json['image_url'])){
128 return new JsonResponse(['message' => "Erreur 400: Bad Request"], JsonResponse::HTTP_BAD_REQUEST); // code 400
129 }
130
131 $image_data = self::curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents
132 if(!$image_data){
133 return new JsonResponse(['message' => "Erreur, le serveur n'a pas réussi à télécharger l'image."], JsonResponse::HTTP_BAD_REQUEST); // code 400
134 }
135
136 $dest = 'user_data/images/';
137 if(!is_dir($dest)){ // Vérifier si le répertoire existe, sinon le créer
138 mkdir($dest, 0755, true);
139 }
140
141 $url_path = parse_url($json['image_url'], PHP_URL_PATH);
142 $name = Security::secureFileName(pathinfo($url_path, PATHINFO_FILENAME));
143 $extension = strtolower(pathinfo($url_path, PATHINFO_EXTENSION));
144 if(!in_array($extension, self::ALLOWED_EXTENSIONS) || $extension === 'jpg'){
145 $extension = 'jpeg';
146 }
147 $local_path = uniqid($dest . $name . '_') . '.' . $extension;
148
149 if(self::imagickCleanAndWriteImage($image_data, $local_path)){ // recréer l’image pour la nettoyer
150 return new JsonResponse(['location' => $local_path]); // nouvelle adresse
151 }
152 else{
153 return new JsonResponse(['message' => 'Erreur image non valide', 'format' => $extension], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
154 }
155 }
156
157 // collage simple d'une image (base64 dans le presse-papier) non encapsulée dans du HTML
158 static public function uploadImageBase64(): JsonResponse
159 {
160 $json = json_decode(file_get_contents('php://input'), true);
161 $dest = 'user_data/images/';
162
163 if(!is_dir($dest)){
164 mkdir($dest, 0755, true);
165 }
166
167 // détection de data:image/ et de ;base64, et capture du format dans $type
168 if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){
169 return new JsonResponse(['message' => 'Données image base64 manquantes ou invalides'], JsonResponse::HTTP_BAD_REQUEST); // code 400
170 }
171
172 $extension = strtolower($type[1]); // dans (\w+)
173 if(!in_array($extension, self::ALLOWED_EXTENSIONS)){
174 $extension = 'jpeg';
175 }
176
177 $name = 'pasted_image';
178 $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire
179 if($image_data === false){
180 return new JsonResponse(['message' => 'Décodage base64 invalide'], JsonResponse::HTTP_BAD_REQUEST); // code 400
181 }
182 $local_path = uniqid($dest . $name . '_') . '.' . $extension;
183
184 if(self::imagickCleanAndWriteImage($image_data, $local_path)){
185 return new JsonResponse(['location' => $local_path]);
186 }
187 else{
188 return new JsonResponse(['message' => 'Erreur image non valide', 'format' => $extension], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
189 }
190 }
191} \ No newline at end of file
diff --git a/src/controller/MaintenanceController.php b/src/controller/MaintenanceController.php
deleted file mode 100644
index 5b67fa8..0000000
--- a/src/controller/MaintenanceController.php
+++ /dev/null
@@ -1,147 +0,0 @@
1<?php
2// src/controller/MaintenanceController.php
3
4declare(strict_types=1);
5
6use Doctrine\ORM\EntityManager;
7use App\Entity\log;
8use Symfony\Component\HttpFoundation\Request;
9use Symfony\Component\HttpFoundation\JsonResponse;
10use Symfony\Component\HttpFoundation\BinaryFileResponse;
11use Symfony\Component\HttpFoundation\ResponseHeaderBag;
12use Symfony\Component\HttpFoundation\RedirectResponse;
13
14class MaintenanceController
15{
16 static public function getLogs(EntityManager $entityManager): JsonResponse
17 {
18 $data = $entityManager->getRepository(Log::class)->findAll();
19 if(empty($data)){
20 return new JsonResponse(['success' => false]);
21 }
22 else{
23 $view = '<h4>Table ' . TABLE_PREFIX . 'log de la base de données</h4>
24 <table>
25 <thead>
26 <tr>
27 <th>date et heure (Greenwich)</th>
28 <th>connexion réussie</th>
29 </tr>
30 </thead>
31 <tbody>';
32 foreach($data as $entry){
33 $view .= '<tr>
34 <td>' . $entry->getFormatedDate() . '</td>
35 <td>' . ($entry->getSuccess() ? 'oui' : 'non') . '</td>
36 </tr>';
37 }
38 $view .= '</tbody></table>';
39 return new JsonResponse(['success' => true, 'view' => $view]);
40 }
41 }
42 static public function eraseLogs(EntityManager $entityManager): JsonResponse
43 {
44 try{
45 $table = $entityManager->getClassMetadata(Log::class)->getTableName();
46 $entityManager->getConnection()->executeStatement("TRUNCATE TABLE {$table}"); // SQL donné à DBAL
47 return new JsonResponse(['success' => true]);
48 }
49 catch(Exception $e){
50 return new JsonResponse(['success' => false, 'error' => $e->getMessage()]);
51 }
52 }
53
54 static public function getLastDump(EntityManager $entityManager): BinaryFileResponse|RedirectResponse
55 {
56 try{
57 $backup_list = Backup::getBackupList();
58 $nb = count($backup_list);
59
60 if($nb <= 0){ // se produit à la première connexion en mode admin pour une raison algorithimque
61 Backup::mySQLdump($entityManager, 'auto');
62 $backup_list = Backup::getBackupList();
63 $nb = count($backup_list);
64 if($nb <= 0){ // improbable, les dossiers devraient déjà avoir été créés
65 throw new RuntimeException("Le serveur a rencontré une erreur: aucun backup n'est disponible et ce n'est pas normal.");
66 }
67 }
68
69 $file_path = Backup::$backup_dir . '/' . $backup_list[$nb - 1];
70 $response = new BinaryFileResponse($file_path);
71 $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT); // ne pas essayer de l'afficher dans le navigateur
72 }
73 catch(RuntimeException $e){
74 $_SESSION['flash_message'] = $e->getMessage();
75 $response = new RedirectResponse((string) new URL(['page' => 'maintenance']));
76 }
77 return $response;
78 }
79 static public function getAllMedia(): BinaryFileResponse|RedirectResponse
80 {
81 try{
82 $file_path = '../var/' . UserDataService::createZip('all_media.zip', ['user_data/assets', 'user_data/images', 'user_data/media']);
83 $response = new BinaryFileResponse($file_path);
84 $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT); // ne pas essayer de l'afficher dans le navigateur
85 }
86 catch(RuntimeException $e){
87 $_SESSION['flash_message'] = $e->getMessage();
88 $response = new RedirectResponse((string) new URL(['page' => 'maintenance']));
89 }
90 return $response;
91 }
92
93 // parce qu'il faut un contrôleur
94 static public function handleBackupSelection(EntityManager $entityManager, Request $request): RedirectResponse
95 {
96 $selected_file = $request->request->get('selected_sql');
97 $url = new URL;
98 if($request->query->has('from')){
99 $url->addParams(['page' => $request->query->get('from')]);
100 }
101
102 try{
103 if(pathinfo($selected_file)['extension'] !== 'sql'){ // pas censé se produire en fait
104 throw new Exception("charger un fichier au format SQL");
105 }
106 Backup::restoreDatabase($entityManager, $selected_file, ['user']);
107
108 $_SESSION['flash_message'] = "La base de données a été restaurée avec succès !!";
109 }
110 catch(Exception $e){
111 $_SESSION['flash_message'] = "Une erreur s'est produite: " . $e->getMessage();
112 }
113
114 return new RedirectResponse((string)$url);
115 }
116
117 static public function downloadSQL(EntityManager $entityManager, Request $request): RedirectResponse
118 {
119 $uploaded_file = $request->files->get('uploaded_sql');
120 $date = new DateTime;
121 $server_place = Config::$database . '_' . $date->format('Y-m-d') . '_uploaded.sql';
122 $url = new URL;
123 if($request->query->has('from')){
124 $url->addParams(['page' => $request->query->get('from')]);
125 }
126
127 try{
128 if(pathinfo($uploaded_file->getClientOriginalName())['extension'] !== 'sql'){
129 throw new Exception("Charger un fichier au format SQL");
130 }
131 //echo $uploaded_file->getSize(); // à garder de côté au cas où
132
133 // enregistrer le fichier
134 $uploaded_file->move(Backup::$backup_dir, $server_place);
135
136 // s'en servir
137 Backup::restoreDatabase($entityManager, $server_place, ['user']);
138
139 $_SESSION['flash_message'] = "La base de données a été restaurée avec succès !!";
140 }
141 catch(Exception $e){
142 $_SESSION['flash_message'] = "Une erreur s'est produite: " . $e->getMessage();
143 }
144
145 return new RedirectResponse((string)$url);
146 }
147} \ No newline at end of file
diff --git a/src/controller/MenuAndPathsController.php b/src/controller/MenuAndPathsController.php
deleted file mode 100644
index 9bd6ad1..0000000
--- a/src/controller/MenuAndPathsController.php
+++ /dev/null
@@ -1,219 +0,0 @@
1<?php
2// src/controller/MenuAndPathsController.php
3
4declare(strict_types=1);
5
6use App\Entity\Page;
7use Doctrine\ORM\EntityManager;
8use Symfony\Component\HttpFoundation\JsonResponse;
9use Symfony\Component\HttpFoundation\RedirectResponse;
10
11class MenuAndPathsController
12{
13 static public function newUrlMenuEntry(EntityManager $entityManager): RedirectResponse
14 {
15 Model::$menu = new Menu($entityManager);
16 $previous_page = Model::$menu->findPageById((int)$_POST["location"]); // (int) à cause de declare(strict_types=1);
17 $parent = $previous_page->getParent();
18
19 $url_input = trim($_POST["url_input"]); // faire htmlspecialchars à l'affichage
20 if(!filter_var($url_input, FILTER_VALIDATE_URL) || !str_starts_with($url_input, 'http')){
21 // utiliser une flash error
22 return new RedirectResponse((string)new URL(['page' => $_GET['from'], 'error' => 'invalide_url']));
23 }
24
25 $page = new Page(
26 trim(htmlspecialchars($_POST["label_input"])),
27 $url_input, '',
28 true, true, false,
29 $previous_page->getPosition(),
30 $parent); // peut et DOIT être null si on est au 1er niveau
31
32 // on a donné à la nouvelle entrée la même position qu'à la précédente,
33 // addChild l'ajoute à la fin du tableau "children" puis on trie
34 // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position
35 if(!$parent){
36 $parent = Model::$menu;
37 }
38 $parent->addChild($page); // true pour réindexer les positions en BDD
39 $parent->reindexPositions();
40
41 $entityManager->persist($page);
42 $entityManager->flush();
43 return new RedirectResponse((string)new URL(['page' => $_GET['from']]));
44 }
45
46 // on pourrait utiliser FormValidation ici
47 static public function editUrl(EntityManager $entityManager, array $json): JsonResponse
48 {
49 $url_data = trim($json['input_data']); // garder htmlspecialchars pour l'affichage
50 $page = $entityManager->find('App\Entity\Page', $json['id']);
51
52 if(!$page){
53 return new JsonResponse(['success' => false, 'message' => "id invalide"]);
54 }
55 elseif(!in_array($json['field'], ['url_name', 'url_content'])){
56 return new JsonResponse(['success' => false, 'message' => "champ invalide"]);
57 }
58 elseif($json['field'] === 'url_content' && (!filter_var($url_data, FILTER_VALIDATE_URL) || !str_starts_with($url_data, 'http'))){
59 return new JsonResponse(['success' => false, 'message' => "la chaîne envoyée n'est pas une URL valide"]);
60 }
61 else{
62 if($json['field'] === 'url_name'){
63 $page->setPageName($url_data);
64 }
65 elseif($json['field'] === 'url_content'){
66 $page->setEndOfPath($url_data);
67 }
68 $entityManager->flush();
69 return new JsonResponse(['success' => true, 'url_data' => $url_data]);
70 }
71 }
72
73 static public function deleteUrlMenuEntry(EntityManager $entityManager): RedirectResponse
74 {
75 Model::$menu = new Menu($entityManager);
76 $page = Model::$menu->findPageById((int)$_POST["delete"]);
77 $parent = $page->getParent();
78 if($parent == null){
79 $parent = Model::$menu;
80 }
81
82 $parent->removeChild($page); // suppression de $children avant de trier
83 $parent->reindexPositions();
84
85 $entityManager->remove($page); // suppression en BDD
86 $entityManager->flush();
87 return new RedirectResponse((string)new URL(['page' => $_GET['from']]));
88 }
89
90 static public function MoveOneLevelUp(EntityManager $entityManager, array $json): JsonResponse
91 {
92 $id = $json['id'];
93 $page = Model::$menu->findPageById((int)$id);
94
95 $parent = $page->getParent(); // peut être null
96 if($parent === null){
97 // 1er niveau: ne rien faire
98 return new JsonResponse(['success' => false, 'message' => 'nothing to do']);
99 }
100 // BDD
101 else{
102 $page->setPosition($parent->getPosition() + 1); // nouvelle position
103
104 // 2ème niveau: le parent devient $menu, puis null après tri
105 if($parent->getParent() === null){
106 // connexion dans les deux sens
107 $page->setParent(Model::$menu); // => pour la persistance
108
109 //Model::$menu->addChild($page); // => pour sortChildren
110 $page->getParent()->addChild($page); // => pour sortChildren
111 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
112 $page->setParent(null);
113
114 // affichage
115 $page->setPagePath($page->getEndOfPath());
116 $page->fillChildrenPagePath();
117 }
118 // 3ème niveau et plus
119 else{
120 $page->setParent($parent->getParent()); // nouveau parent
121 $page->getParent()->addChild($page); // => pour sortChildren
122 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
123 $page->fillChildrenPagePath($page->getParent()->getPagePath());
124 }
125 $entityManager->flush();
126
127 // affichage
128 $parent->removeChild($page);
129 $nav_builder = new NavBuilder();
130 $menu_builder = new MenuBuilder(null, false);
131 return new JsonResponse(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
132 }
133 }
134
135 static public function MoveOneLevelDown(EntityManager $entityManager, array $json): JsonResponse
136 {
137 $id = $json['id'];
138 $page = Model::$menu->findPageById((int)$id);
139
140 $parent = $page->getParent(); // peut être null
141 if($parent === null){
142 $parent = Model::$menu;
143 }
144
145 // BDD
146 $parent->sortChildren(true); // trie et réindexe par sécurité: 1, 2, 3...
147 if($page->getPosition() > 1){
148 foreach($parent->getChildren() as $child){
149 if($child->getPosition() === $page->getPosition() - 1){
150 // refus si $parent est une adresse, ça va casser le lien, exemple: index.php?page=chemin/http://un_site_web.fr/vers/ici
151 if(str_starts_with($child->getEndOfPath(), 'http')){
152 return new JsonResponse(['success' => false, 'error' => 'new_parent_is_a_link']);
153 }
154
155 $page->setParent($child);
156 break;
157 }
158 }
159 $page->setPosition(count($page->getParent()->getChildren()) + 1);
160 }
161 $entityManager->flush();
162
163 // affichage
164 $parent->removeChild($page);
165 $page->getParent()->addChild($page);
166 $page->fillChildrenPagePath($page->getParent()->getPagePath()); // variable non mappée $page_path
167 $nav_builder = new NavBuilder();
168 $menu_builder = new MenuBuilder(null, false);
169
170 return new JsonResponse(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
171 }
172
173 static public function SwitchPositions(EntityManager $entityManager, array $json): JsonResponse
174 {
175 $id1 = $json['id1'];
176 $id2 = $json['id2'];
177
178 // vérifier qu'ils ont le même parent
179 $page1 = Model::$menu->findPageById((int)$id1);
180 $page2 = Model::$menu->findPageById((int)$id2);
181
182 // double le contrôle fait en JS
183 if($page1->getParent() === $page2->getParent()) // comparaison stricte d'objet (même instance du parent?)
184 {
185 // inversion
186 $tmp = $page1->getPosition();
187 $page1->setPosition($page2->getPosition());
188 $page2->setPosition($tmp);
189 Model::$menu->sortChildren(true); // modifie tableau children
190 $entityManager->flush();
191
192 // nouveau menu
193 $nav_builder = new NavBuilder();
194 return new JsonResponse(['success' => true, 'nav' => $nav_builder->render()]);
195 }
196 else{
197 return new JsonResponse(['success' => false]);
198 }
199 }
200
201 static public function displayInMenu(EntityManager $entityManager, array $json): JsonResponse
202 {
203 $id = $json['id'];
204 $checked = $json['checked'];
205
206 $page = Model::$menu->findPageById((int)$id);
207 if($page->isHidden() === $checked){
208 $page->setHidden(!$checked);
209 $entityManager->flush();
210
211 // nouveau menu
212 $nav_builder = new NavBuilder();
213 return new JsonResponse(['success' => true, 'nav' => $nav_builder->render()]);
214 }
215 else{
216 return new JsonResponse(['success' => false]);
217 }
218 }
219} \ No newline at end of file
diff --git a/src/controller/PageManagementController.php b/src/controller/PageManagementController.php
deleted file mode 100644
index 11aab09..0000000
--- a/src/controller/PageManagementController.php
+++ /dev/null
@@ -1,362 +0,0 @@
1<?php
2// src/controller/PageManagementController.php
3
4declare(strict_types=1);
5
6use App\Entity\Page;
7use App\Entity\Node;
8use App\Entity\NodeData;
9use App\Entity\EmailForm;
10use App\Entity\Presentation;
11//use App\Entity\Image;
12use Doctrine\ORM\EntityManager;
13use Symfony\Component\HttpFoundation\InputBag;
14use Symfony\Component\HttpFoundation\JsonResponse;
15use Symfony\Component\HttpFoundation\RedirectResponse;
16use Symfony\Component\HttpFoundation\Request;
17
18class PageManagementController
19{
20 /* -- partie page -- */
21 static public function setPageTitle(EntityManager $entityManager, array $json): JsonResponse
22 {
23 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
24 $page->setPageName(htmlspecialchars($json['title']));
25 $entityManager->flush();
26 return new JsonResponse(['success' => true, 'title' => $page->getPageName()]);
27 }
28
29 static public function updatePageMenuPath(EntityManager $entityManager, string $page_menu_path): RedirectResponse
30 {
31 Model::$menu = new Menu($entityManager);
32 Model::$page_path = new Path();
33 $page = Model::$page_path->getLast();
34 $path = htmlspecialchars($page_menu_path);
35
36 // mise en snake_case: filtre caractères non-alphanumériques, minuscule, doublons d'underscore, trim des underscores
37 $path = trim(preg_replace('/_+/', '_', strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $path))), '_');
38 $page->setEndOfPath($path);
39 foreach(Model::$menu->getChildren() as $child){
40 if($child->getEndOfPath() === Model::$page_path->getArray()[0]->getEndOfPath()){
41 $child->fillChildrenPagePath(); // MAJ de $page_path
42 }
43 }
44 $entityManager->flush();
45 return new RedirectResponse((string)new URL(['page' => $page->getPagePath(), 'mode' => 'page_modif']));
46 }
47
48 static public function setPageDescription(EntityManager $entityManager, array $json): JsonResponse
49 {
50 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
51 $page->setDescription(htmlspecialchars($json['description']));
52 $entityManager->flush();
53 return new JsonResponse(['success' => true, 'description' => $page->getDescription()]);
54 }
55
56 static public function newPage(EntityManager $entityManager, InputBag $post): RedirectResponse
57 {
58 // titre et chemin
59 Model::$menu = new Menu($entityManager);
60 $previous_page = Model::$menu->findPageById((int)$post->get("page_location")); // (int) à cause de declare(strict_types=1);
61 $parent = $previous_page->getParent();
62
63 $page = new Page(
64 trim(htmlspecialchars($post->get("page_name"))),
65 trim(htmlspecialchars($post->get("page_name_path"))),
66 trim(htmlspecialchars($post->get("page_description"))),
67 true, true, false,
68 $previous_page->getPosition(),
69 $parent); // peut et DOIT être null si on est au 1er niveau
70
71 // on a donné à la nouvelle entrée la même position qu'à la précédente,
72 // addChild l'ajoute à la fin du tableau "children" puis on trie
73 // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position
74 if($parent == null){
75 $parent = Model::$menu;
76 }
77 $parent->addChild($page);
78 $parent->reindexPositions();
79
80 $page->setPagePath(ltrim($parent->getPagePath() . '/' . $page->getEndOfPath(), '/'));
81
82 $entityManager->persist($page);
83 $entityManager->flush();
84
85 // page créée, direction la page en mode modification pour ajouter des blocs
86 return new RedirectResponse((string)new URL(['page' => $page->getPagePath(), 'mode' => 'page_modif']));
87 }
88
89 static public function deletePage(EntityManager $entityManager, string $page_id): RedirectResponse
90 {
91 $menu = new Menu($entityManager);
92 $page = $menu->findPageById((int)$page_id);
93 $url = new URL;
94
95 // test dernière page
96 // => $menu a un enfant et pas de petits enfants
97 // => $menu->getChildren()->isEmpty() n'est théoriquement pas possible
98 if($menu->getChildren()->isEmpty() || (count($menu->getChildren()) === 1 && $menu->getChildren()[0]->getChildren()->isEmpty())){
99 $url->addParams(['page' => $page->getEndOfPath(), 'error' => 'you_tried_to_remove_the_last_page']);
100 }
101 else{
102 $nodes = $entityManager->getRepository('App\Entity\Node')->findBy(['page' => $page]);
103 $data = [];
104 foreach($nodes as $node){
105 $data[] = $entityManager->getRepository('App\Entity\NodeData')->findOneBy(['node' => $node]);
106 $entityManager->remove($node);
107 }
108 foreach($data as $one_data){
109 $entityManager->remove($one_data);
110 }
111 $entityManager->remove($page); // suppression en BDD
112 $entityManager->flush();
113
114 // destination vers la première page dispo
115 // traite les cas prévus dans le if plus haut
116 $menu->removeChild($page);
117 $next_page = $menu->getChildren()->isEmpty() ? $next_page = $page->getChildren()[0] : $menu->getChildren()[0];
118 $url->addParams(['page' => $next_page->getEndOfPath()]);
119 }
120
121 return new RedirectResponse((string)$url);
122 }
123
124 /* partie "blocs" */
125 static public function addBloc(EntityManager $entityManager, Request $request): RedirectResponse
126 {
127 $model = new Model($entityManager);
128 $model->makeMenuAndPaths(); // on a besoin de page_path qui dépend de menu
129 $page = Model::$page_path->getLast();
130 $model->findUniqueNodeByName('main');
131 $model->findItsChildren();
132 $main = $model->getNode();
133 $position = count($main->getChildren()) + 1; // position dans la fraterie
134
135 if(!in_array($request->request->get("bloc_select"), array_keys(Presentation::BLOCKS), true)){ // 3è param: contrôle du type
136 // utiliser une flash error
137 return new RedirectResponse((string)new URL(['page' => $request->query->get('page'), 'error' => 'bad_bloc_type']));
138 }
139
140 if(in_array($request->request->get("bloc_select"), ['calendar', 'form'])){
141 $page->addCSS($request->request->get("bloc_select"));
142 if($request->request->get("bloc_select") === 'form'){
143 $page->addJS($request->request->get("bloc_select"));
144 }
145 $entityManager->persist($page);
146 }
147
148 $block = new Node($request->request->get("bloc_select"), $position, $main, $page);
149
150 $DataClass = match($request->request->get("bloc_select")){
151 'form' => EmailForm::class,
152 'post_block', 'news_block' => Presentation::class,
153 'calendar' => NodeData::class,
154 default => throw new InvalidArgumentException("Erreur: type de bloc inconnu"),
155 };
156 $data = new $DataClass(['title' => trim(htmlspecialchars($request->request->get("bloc_title")))], $block);
157
158 // valeurs par défaut
159 if($request->request->get("bloc_select") === 'post_block'){
160 $data->setPresentation('fullwidth');
161 }
162 elseif($request->request->get("bloc_select") === 'news_block'){
163 $data->setPresentation('grid');
164 }
165 elseif($request->request->get("bloc_select") === 'galery'){
166 $data->setPresentation('mosaic'); // un jour on mettra carousel
167 }
168 // else = null par défaut
169
170 $entityManager->persist($block);
171 $entityManager->persist($data);
172 $entityManager->flush();
173 return new RedirectResponse((string)new URL(['page' => $request->query->get('page'), 'mode' => 'page_modif']));
174 }
175
176 static public function deleteBloc(EntityManager $entityManager, Request $request): RedirectResponse
177 {
178 $model = new Model($entityManager);
179 $model->makeMenuAndPaths();
180 $model->findUniqueNodeByName('main');
181 $model->findItsChildren();
182 $main = $model->getNode();
183
184 $block = null;
185 $type = '';
186 $nb_same_type = 0;
187 foreach($main->getChildren() as $child){
188 if($child->getId() === (int)$request->request->get('delete_bloc_id')){
189 $block = $child;
190 $type = $block->getName();
191 }
192 if($child->getName() === $type){
193 $nb_same_type++;
194 }
195 }
196
197 // nettoyage fichiers CSS et JS si on retire le derner bloc de ce type
198 if($nb_same_type === 1 && in_array($block->getName(), ['calendar', 'form'])){
199 $page = $block->getPage();
200 $page->removeCSS($block->getName());
201 if($block->getName() === 'form'){
202 $page->removeJS($block->getName());
203 }
204 }
205
206 if(!empty($block)){ // si $block est null c'est que le HTML a été modifié volontairement
207 $main->removeChild($block); // réindex le tableau $children au passage
208 $main->reindexPositions();
209 if(isset($page)){
210 $entityManager->persist($page);
211 }
212 $block->getNodeData()->setNode(null);
213 $entityManager->remove($block);
214 try{
215 $entityManager->flush();
216 }
217 catch(Exception $e){
218 // utiliser une flash error
219 return new RedirectResponse((string)new URL(['page' => $request->query->get('page'), 'mode' => 'page_modif', 'error' => $e->getMessage()]));
220 }
221 }
222
223 return new RedirectResponse((string)new URL(['page' => $request->query->get('page'), 'mode' => 'page_modif']));
224 }
225
226 static public function renameBloc(EntityManager $entityManager, array $json): JsonResponse
227 {
228 if(isset($json['bloc_title']) && $json['bloc_title'] !== null && isset($json['bloc_id']) && is_int($json['bloc_id'])){
229 $model = new Model($entityManager);
230 $model->findNodeById($json['bloc_id']);
231
232 // le titre (du JSON en BDD) est récupéré sous forme de tableau, modifié et renvoyé
233 $data = $model->getNode()->getNodeData()->getData();
234 $data['title'] = htmlspecialchars($json['bloc_title']);
235 $model->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title']));
236
237 $entityManager->flush();
238 return new JsonResponse(['success' => true, 'title' => $data['title']]);
239 }
240 else{
241 return new JsonResponse(['success' => false]);
242 }
243 }
244
245 static public function SwitchBlocsPositions(EntityManager $entityManager, array $json, string $page): JsonResponse
246 {
247 if(isset($json['id1']) && is_int($json['id1']) && isset($json['id2']) && is_int($json['id2']) && isset($page)){
248 $model = new Model($entityManager);
249 $model->makeMenuAndPaths(); // true pour $model->findItsChildren();
250 $model->findUniqueNodeByName('main');
251 $model->findItsChildren();
252 $main = $model->getNode();
253 $main->sortChildren(true); // régénère les positions avant inversion
254
255 $bloc1 = null;
256 $bloc2 = null;
257 foreach($main->getChildren() as $child){
258 if($child->getId() === $json['id1']){
259 $bloc1 = $child;
260 break;
261 }
262 }
263 foreach($main->getChildren() as $child){
264 if($child->getId() === $json['id2']){
265 $bloc2 = $child;
266 break;
267 }
268 }
269
270 // inversion
271 $tmp = $bloc1->getPosition();
272 $bloc1->setPosition($bloc2->getPosition());
273 $bloc2->setPosition($tmp);
274
275 $entityManager->flush();
276 return new JsonResponse(['success' => true]);
277 }
278 else{
279 return new JsonResponse(['success' => false]);
280 }
281 }
282
283 static public function changeArticlesOrder(EntityManager $entityManager, array $json): JsonResponse
284 {
285 if(isset($json['id']) && isset($json['chrono_order'])){
286 $model = new Model($entityManager);
287 $model->findNodeById($json['id']);
288
289 if($json['chrono_order'] === 'chrono'){
290 $chrono_order = true;
291 }
292 elseif($json['chrono_order'] === 'antichrono'){
293 $chrono_order = false;
294 }
295 else{
296 return new JsonResponse(['success' => false]);
297 }
298 $model->getNode()->getNodeData()->setChronoOrder($chrono_order);
299 $entityManager->flush();
300
301 return new JsonResponse(['success' => true, 'chrono_order' => $json['chrono_order']]);
302 }
303 else{
304 return new JsonResponse(['success' => false]);
305 }
306 }
307
308 static public function changePresentation(EntityManager $entityManager, array $json): JsonResponse
309 {
310 if(isset($json['id']) && isset($json['presentation'])){
311 $model = new Model($entityManager);
312 $model->findNodeById($json['id']);
313
314 if(in_array($json['presentation'], array_keys(Presentation::PRESENTATIONS))){
315 $model->getNode()->getNodeData()->setPresentation($json['presentation']);
316 $entityManager->flush();
317
318 $response_data = ['success' => true, 'presentation' => $json['presentation']];
319 if($json['presentation'] === 'grid'){
320 $response_data['cols_min_width'] = $model->getNode()->getNodeData()->getColsMinWidth();
321 }
322 return new JsonResponse($response_data);
323 }
324 else{
325 return new JsonResponse(['success' => false]);
326 }
327 }
328 else{
329 return new JsonResponse(['success' => false]);
330 }
331 }
332 static public function changeColsMinWidth(EntityManager $entityManager, array $json): JsonResponse
333 {
334 if(isset($json['id']) && isset($json['cols_min_width'])){
335 $model = new Model($entityManager);
336 $model->findNodeById($json['id']);
337 $model->getNode()->getNodeData()->setColsMinWidth((int)$json['cols_min_width']); // attention conversion?
338
339 $entityManager->flush();
340 return new JsonResponse(['success' => true, 'cols_min_width' => $json['cols_min_width']]);
341 }
342 else{
343 return new JsonResponse(['success' => false]);
344 }
345 }
346 static public function changePaginationLimit(EntityManager $entityManager, array $json): JsonResponse
347 {
348 if(isset($json['id']) && isset($json['pagination_limit'])){
349 $model = new Model($entityManager);
350 $model->findNodeById($json['id']);
351 $old_limit = $model->getNode()->getNodeData()->getPaginationLimit() ?? 12;
352 $model->getNode()->getNodeData()->setPaginationLimit((int)$json['pagination_limit']); // attention conversion?
353
354 $entityManager->flush();
355
356 return new JsonResponse(['success' => true, 'old_limit' => $old_limit, 'new_limit' => $json['pagination_limit']]);
357 }
358 else{
359 return new JsonResponse(['success' => false]);
360 }
361 }
362} \ No newline at end of file
diff --git a/src/controller/UserController.php b/src/controller/UserController.php
deleted file mode 100644
index b68421f..0000000
--- a/src/controller/UserController.php
+++ /dev/null
@@ -1,230 +0,0 @@
1<?php
2// src/controller/UserController.php
3//
4/* actuellement un fourre-tout de méthodes en rapport avec les utilisateurs
5pour l'améliorer on pourrait appliquer le principe de reponsabilité unique
6=> UserController devrait se limiter à gérer des requêtes et réponses (changement transparent pour le routeur)
7il instancierait un classe correspondant au formulaire (prend POST et SESSION) et une classe "métier" UserService
8=> UserService contiendrait des méthodes utilisant l'objet formulaire pour agir sur la BDD
9=> les formulaires peuvent tenir dans une classe "UserUpdateForm" avec des stratégies ou plusieurs, les données y sont validées
10=> il est aussi possible de découper UserController en contrôleurs par fonctionnalité:
11Auth (connexion, deconnexion), User (infos, choix photo), Account (créer, supprimer compte), Avatar (upload photo...)
12*/
13
14declare(strict_types=1);
15
16use Doctrine\ORM\EntityManager;
17use App\Entity\User;
18use App\Entity\Log;
19use Symfony\Component\HttpFoundation\RedirectResponse;
20
21class UserController
22{
23 // account
24 static public function createAdminUser(EntityManager $entityManager): RedirectResponse
25 {
26 unset($_SESSION['user']);
27
28 $form = new FormValidation($_POST, ValidationStrategy::CreateUser);
29
30 $url = new URL;
31 $error = '';
32 if($form->validate()){
33 $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
34 $user = new User($_POST['login'], 'admin', $password);
35 $entityManager->persist($user);
36 $entityManager->flush();
37 }
38 else{
39 $error = $form->getError();
40 }
41
42 if(!empty($error)){
43 $url->addParams(['error' => $error]);
44 }
45
46 return new RedirectResponse((string)$url);
47 }
48
49 // account
50 //static public function createUser(EntityManager $entityManager){}
51
52 // auth
53 static public function connect(EntityManager $entityManager): RedirectResponse
54 {
55 $url = new URL;
56 if(IS_ADMIN){ // déjà connecté?
57 return new RedirectResponse((string)$url);
58 }
59 unset($_SESSION['user']);
60
61 $form = new FormValidation($_POST, ValidationStrategy::Connection);
62
63 $error = '';
64 if($form->validate()){
65 // à mettre dans une classe métier UserService, Authentication, AuthService?
66 $user = self::getUserByName($_POST['login'], $entityManager);
67 if(!empty($user) && $_POST['login'] === $user->getLogin() && password_verify($_POST['password'], $user->getPassword())){
68 $log = new Log(true);
69
70 // protection fixation de session, si l'attaquant crée un cookie de session, il est remplacé
71 session_regenerate_id(true);
72 $_SESSION['user']['id'] = $user->getId();
73 $_SESSION['user']['username'] = $user->getLogin();
74 $_SESSION['user']['role'] = $user->getRole();
75
76 EmailService::cleanEmails($entityManager);
77
78 try{
79 if(file_exists('../var/backups')){
80 Backup::mySQLdump($entityManager, 'auto'); // créer un nouveau backup, sauf si les dossiers nécessaires sont encore à créer
81 }
82 }
83 catch(RuntimeException $e){
84 echo '<script>window.error_message = "' . $e->getMessage() . '";</script>';
85 }
86
87 $url->addParams(isset($_GET['from']) ? ['page' => $_GET['from']] : []);
88 isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : '';
89 }
90 else
91 {
92 $log = new Log(false);
93 $error = 'bad_login_or_password';
94 }
95 $entityManager->persist($log);
96 $entityManager->flush();
97 }
98 else{
99 $error = $form->getError();
100 }
101
102 if(!empty($error)){
103 sleep(1); // défense basique à la force brute
104 $url->addParams(['page' => 'connection']);
105 isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null;
106 isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : null;
107 $url->addParams(['error' => $error]);
108 }
109
110 return new RedirectResponse((string)$url);
111 }
112
113 // auth
114 static public function disconnect(): RedirectResponse
115 {
116 // nettoyage complet
117 unset($_SESSION['user']); // mémoire vive
118 session_destroy(); // fichier côté serveur
119 setcookie('PHPSESSID', '', time() - 86400, '/'); // cookie de session
120
121 // retour même page
122 $url = new URL;
123 isset($_GET['from']) ? $url->addParams(['page' => $_GET['from']]) : '';
124 isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : '';
125 return new RedirectResponse((string)$url);
126 }
127
128 // user
129 static public function updateUsername(EntityManager $entityManager): RedirectResponse
130 {
131 if(!IS_ADMIN){ // superflux, fait dans le routeur
132 return self::disconnect();
133 }
134
135 $url = new URL(['page' => 'user_edit']);
136 isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null;
137
138 $form = new FormValidation($_POST, ValidationStrategy::UsernameUpdate);
139
140 $error = '';
141 if($form->validate()){
142 // à mettre dans une classe métier UserService?
143 $user = self::getUserByName($_POST['login'], $entityManager);
144 if(password_verify($_POST['password'], $user->getPassword())){
145 $user->setLogin($_POST['new_login']);
146 $entityManager->flush();
147 $_SESSION['user']['username'] = $_POST['new_login'];
148
149 $url->addParams(['success_username' => 'new_login']);
150 $error = '';
151 }
152 else{
153 $error = 'bad_login_or_password';
154 }
155 }
156 else{
157 $error = $form->getError();
158 }
159
160 if(!empty($error)){
161 sleep(1);
162 $url->addParams(['error_username' => $error]);
163 }
164 return new RedirectResponse((string)$url);
165 }
166
167 // user
168 static public function updatePassword(EntityManager $entityManager): RedirectResponse
169 {
170 if(!IS_ADMIN){ // superflux, fait dans le routeur
171 return self::disconnect();
172 }
173
174 $url = new URL(['page' => 'user_edit']);
175 isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null;
176
177 $form = new FormValidation($_POST, ValidationStrategy::PasswordUpdate);
178
179 $error = '';
180 if($form->validate()){
181 // à mettre dans une classe métier UserService?
182 $user = self::getUserByName($_POST['login'], $entityManager);
183 if(password_verify($_POST['password'], $user->getPassword())){
184 $new_password = password_hash($_POST['new_password'], PASSWORD_DEFAULT);
185 $user->setPassword($new_password);
186 $entityManager->flush();
187
188 $url->addParams(['success_password' => 'new_password']);
189 $error = '';
190 }
191 else{
192 $error = 'bad_login_or_password';
193 }
194 }
195 else{
196 $error = $form->getError();
197 }
198
199 if(!empty($error)){
200 sleep(1);
201 $url->addParams(['error_password' => $error]);
202 }
203 return new RedirectResponse((string)$url);
204 }
205
206 // dans une classe mère ou un trait après découpage de UserController?
207 static private function getUserByName(string $login, EntityManager $entityManager): ?User
208 {
209 $users = $entityManager->getRepository(User::class)->findBy(['login' => $login]);
210 foreach($users as $user){
211 if($user->getLogin() === $login){
212 return $user;
213 }
214 }
215 return null;
216 }
217
218 static public function getUserById(int $id, EntityManager $entityManager): ?User
219 {
220 return $entityManager->find(User::class, $id);
221 }
222
223 // dans une classe Form?
224 // erreurs à la création des mots de passe
225 static private function removeSpacesTabsCRLF(string $chaine): string
226 {
227 $cibles = [' ', "\t", "\n", "\r"]; // doubles quotes !!
228 return(str_replace($cibles, '', $chaine));
229 }
230} \ No newline at end of file
diff --git a/src/controller/ViewController.php b/src/controller/ViewController.php
deleted file mode 100644
index d1aaee7..0000000
--- a/src/controller/ViewController.php
+++ /dev/null
@@ -1,63 +0,0 @@
1<?php
2// src/controller/ViewController.php
3
4declare(strict_types=1);
5
6use Doctrine\ORM\EntityManager;
7use Symfony\Component\HttpFoundation\Request;
8use Symfony\Component\HttpFoundation\Response;
9use Symfony\Component\HttpFoundation\RedirectResponse;
10
11class ViewController{
12 const SPECIAL_PAGES = ['article', 'new_page', 'menu_paths', 'user_edit', 'connection', 'emails', 'maintenance'];
13
14 static function getWebPage(EntityManager $entityManager, Request $request): Response
15 {
16 /* 1/ 1er contrôle des paramètres */
17
18 // mode modification d'une page
19 if(IS_ADMIN
20 && $request->query->has('mode') && $request->query->get('mode') === 'page_modif'
21 && !in_array(CURRENT_PAGE, self::SPECIAL_PAGES))
22 {
23 MainBuilder::$modif_mode = true;
24 }
25 // page article: mode création et erreurs d'id
26 if(CURRENT_PAGE === 'article'){
27 if(IS_ADMIN){
28 if(!$request->query->has('id')){
29 return new RedirectResponse((string)new URL(['page' => $request->query->get('from') ?? '']));
30 }
31 else{
32 // mode création d'article
33 // l'id du bloc et 'from=' sont vérifiés dans ArticleController::editorSubmit
34 if($request->query->get('id')[0] === 'n' && $request->query->has('from') && !empty($request->query->get('from'))){
35 NewBuilder::$new_article_mode = true;
36 }
37 }
38 }
39 elseif($request->query->get('id')[0] === 'n'){ // accès page nouvelle article interdit sans être admin
40 return new RedirectResponse((string)new URL(['page' => $request->query->get('from') ?? '']));
41 }
42 }
43 // pas de else, l'id dans l'URL n'a pas d'effet ailleurs
44
45
46 /* 2/ accès au modèle */
47 $model = new Model($entityManager);
48 $model->makeMenuAndPaths();
49 $model->getWholePageData($request);
50
51
52 /* 3/ 2ème contrôle des paramètres avec les données récupérées */
53
54 // article non trouvé en BDD
55 if(CURRENT_PAGE === 'article' && !IS_ADMIN && $model->getNode()->getNodeByName('main')->getAdoptedChild() === null){
56 return new RedirectResponse((string)new URL(['page' => $request->query->get('from') ?? '']));
57 }
58
59
60 /* 4/ construction de la page avec builders et vues */
61 return new Response((new ViewDirector)->buildHTML($model->getNode()));
62 }
63} \ No newline at end of file