aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2025-10-03 02:28:22 +0200
committerpolo <ordipolo@gmx.fr>2025-10-03 02:28:22 +0200
commitd6d7351259e104ab10b5dda3483c281830ce4ff3 (patch)
treeec555bcbade2ceaa348f3108e585af1273a0c94a
parentf5cb6249dfb339f8e48e49dc131c6efa09c92ecc (diff)
downloadcms-d6d7351259e104ab10b5dda3483c281830ce4ff3.zip
pagination partie 1, ordre des articles avec ORDER BY, optimisations dans ViewController
-rw-r--r--src/controller/Director.php79
-rw-r--r--src/controller/ViewController.php31
-rw-r--r--src/model/entities/Node.php6
-rw-r--r--src/model/entities/NodeData.php8
4 files changed, 98 insertions, 26 deletions
diff --git a/src/controller/Director.php b/src/controller/Director.php
index 8be9b59..4b9293c 100644
--- a/src/controller/Director.php
+++ b/src/controller/Director.php
@@ -6,6 +6,8 @@ declare(strict_types=1);
6use Doctrine\ORM\EntityManager; 6use Doctrine\ORM\EntityManager;
7use App\Entity\Page; 7use App\Entity\Page;
8use App\Entity\Node; 8use App\Entity\Node;
9//use Doctrine\ORM\QueryBuilder;
10use Symfony\Component\HttpFoundation\Request;
9 11
10class Director 12class Director
11{ 13{
@@ -37,30 +39,91 @@ class Director
37 } 39 }
38 40
39 // affichage d'une page ordinaire 41 // affichage d'une page ordinaire
40 public function makeRootNode(string $id = ''): void 42 public function getWholePageData(Request $request): void
41 { 43 {
42 // on récupère toutes les entrées 44 $id = CURRENT_PAGE === 'article' ? htmlspecialchars($request->query->get('id')) : '';
43 $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page OR n.page IS null'; 45
44 if($id == '') 46 if($id === '') // page "normale"
45 { 47 {
48 // tous les noeuds sauf les articles, tri par page
49 $dql = "SELECT n FROM App\Entity\Node n WHERE n.name_node != 'new' AND n.name_node != 'post' AND (n.page = :page OR n.page IS null)";
46 $bulk_data = $this->entityManager 50 $bulk_data = $this->entityManager
47 ->createQuery($dql) 51 ->createQuery($dql)
48 ->setParameter('page', $this->page) 52 ->setParameter('page', $this->page)
49 ->getResult(); 53 ->getResult();
54
55 // groupes d'articles triés par bloc, permet de paginer par bloc
56 foreach($bulk_data as $parent_block){
57 if(Blocks::hasPresentation($parent_block->getName())){ // = post_block ou news_block
58 $qb = $this->entityManager->createQueryBuilder();
59 $qb->select('n')
60 ->from('App\Entity\Node', 'n')
61 ->where('n.parent = :parent')
62 ->setParameter('parent', $parent_block);
63
64 if($parent_block->getName() === 'post_block'){
65 $qb->orderBy('n.position');
66 }
67 elseif($parent_block->getName() === 'news_block'){
68 $qb->join('n.article', 'a');
69 if($parent_block->getNodeData()->getChronoOrder() ?? false){ // ordre antichrono par défaut
70 $qb->orderBy('a.date_time', 'ASC');
71 }
72 else{
73 $qb->orderBy('a.date_time', 'DESC');
74 }
75 }
76
77 // pagination
78 $limit = $parent_block->getNodeData()->getPaginationLimit() ?? 0; // 0 par défaut = pas de pagination, sinon 12 rend bien avec des grilles de 2, 3 ou 4 colonnes
79 if($limit > 0){
80 //$this->paginateWithCursor($qb, $request->query->get('last_position') ?? 0, $limit);
81 $qb->andWhere('n.position > :last_position')
82 ->setParameter('last_position', $request->query->get('last_position') ?? 0)
83 ->setMaxResults($limit);
84
85 $nb_pages = $this->getNumberOfPages($parent_block, $limit); // nombres de "pages" d'articles
86 if($nb_pages > 1){
87 //$parent_block->setNumberOfPages($nb_pages); // => navigation en HTML
88 }
89 }
90
91 $bulk_data = array_merge($bulk_data, $qb->getQuery()->getResult());
92 }
93 }
50 } 94 }
51 else // avec $_GET['id'] dans l'URL 95 else // page "article"
52 { 96 {
53 $dql .= ' OR n.id_node = :id'; 97 $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page OR n.page IS null OR n.id_node = :id';
54 $bulk_data = $this->entityManager 98 $bulk_data = $this->entityManager
55 ->createQuery($dql) 99 ->createQuery($dql)
56 ->setParameter('page', $this->page) 100 ->setParameter('page', $this->page)
57 ->setParameter('id', $id) 101 ->setParameter('id', $id)
58 ->getResult(); 102 ->getResult();
59 } 103 }
60 $this->feedRootNodeObjects($bulk_data); 104 $this->makeNodeTree($bulk_data);
105 }
106
107 /*private function paginateWithCursor(QueryBuilder $qb, int $last_position = 0, int $limit = 0): void
108 {
109 $qb->andWhere('n.position > :last_position')
110 ->setParameter('last_position', $last_position)
111 ->setMaxResults($limit);
112 }*/
113
114 // requête à part n'alimentant pas $bulk_data
115 // fonctionnalité offerte par le Paginator de doctrine si on décidait de s'en servir
116 private function getNumberOfPages(Node $parent_block, int $limit): int
117 {
118 $dql = 'SELECT COUNT(n.id_node) FROM App\Entity\Node n WHERE n.parent = :parent';
119 $nb_articles = $this->entityManager
120 ->createQuery($dql)
121 ->setParameter('parent', $parent_block)
122 ->getSingleScalarResult();
123 return (int)ceil($nb_articles / $limit); // que PHP fasse une division non euclidienne (pas comme en C) nous arrange ici
61 } 124 }
62 125
63 private function feedRootNodeObjects(array $bulk_data): void // $bulk_data = tableau de Node 126 private function makeNodeTree(array $bulk_data): void // $bulk_data = tableau de Node
64 { 127 {
65 // puis on les range 128 // puis on les range
66 // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD) 129 // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD)
diff --git a/src/controller/ViewController.php b/src/controller/ViewController.php
index 9117f0f..9818c6e 100644
--- a/src/controller/ViewController.php
+++ b/src/controller/ViewController.php
@@ -18,22 +18,15 @@ class ViewController extends AbstractBuilder // ViewController est aussi le prem
18 18
19 public function buildView(EntityManager $entityManager, Request $request): Response 19 public function buildView(EntityManager $entityManager, Request $request): Response
20 { 20 {
21 /* 1/ accès au modèle */ 21 /* 1/ 1er contrôle des paramètres */
22 $director = new Director($entityManager, true);
23 $director->makeRootNode(htmlspecialchars($request->query->get('id') ?? ''));
24 self::$root_node = $director->getNode();
25
26
27 /* 2/ traitement de quelques paramètres */
28 22
29 // mode modification d'une page activé 23 // mode modification d'une page
30 if($_SESSION['admin'] 24 if($_SESSION['admin']
31 && $request->query->has('mode') && $request->query->get('mode') === 'page_modif' 25 && $request->query->has('mode') && $request->query->get('mode') === 'page_modif'
32 && !in_array(CURRENT_PAGE, ['article', 'nouvelle_page', 'menu_chemins', 'user_edit', 'connection'])) 26 && !in_array(CURRENT_PAGE, ['article', 'nouvelle_page', 'menu_chemins', 'user_edit', 'connection']))
33 { 27 {
34 MainBuilder::$modif_mode = true; 28 MainBuilder::$modif_mode = true;
35 } 29 }
36
37 // page article: mode création et erreurs d'id 30 // page article: mode création et erreurs d'id
38 if(CURRENT_PAGE === 'article'){ 31 if(CURRENT_PAGE === 'article'){
39 if($_SESSION['admin']){ 32 if($_SESSION['admin']){
@@ -46,18 +39,30 @@ class ViewController extends AbstractBuilder // ViewController est aussi le prem
46 if($request->query->get('id')[0] === 'n' && $request->query->has('from') && !empty($request->query->get('from'))){ 39 if($request->query->get('id')[0] === 'n' && $request->query->has('from') && !empty($request->query->get('from'))){
47 NewBuilder::$new_article_mode = true; 40 NewBuilder::$new_article_mode = true;
48 } 41 }
49 elseif(self::$root_node->getNodeByName('main')->getAdoptedChild() === null){ // id inconnu
50 return new Response($this->html, 302);
51 }
52 } 42 }
53 } 43 }
54 elseif($request->query->get('id')[0] === 'n'){ // accès page nouvelle article interdit sans être admin 44 elseif($request->query->get('id')[0] === 'n'){ // accès page nouvelle article interdit sans être admin
55 return new Response($this->html, 302); 45 return new Response($this->html, 302);
56 } 46 }
57 } 47 }
48 //else // l'id dans l'adresse n'a pas d'effet sur la suite
49
50
51 /* 2/ accès au modèle */
52 $director = new Director($entityManager, true);
53 $director->getWholePageData($request);
54 self::$root_node = $director->getNode();
55
56
57 /* 3/ 2ème contrôle utilisant les données récupérées */
58
59 // article non trouvé en BDD
60 if(CURRENT_PAGE === 'article' && !$_SESSION['admin'] && self::$root_node->getNodeByName('main')->getAdoptedChild() === null){
61 return new Response($this->html, 302);
62 }
58 63
59 64
60 /* 3/ construction de la page avec builders et vues */ 65 /* 4/ construction de la page avec builders et vues */
61 $this->useChildrenBuilder(self::$root_node); 66 $this->useChildrenBuilder(self::$root_node);
62 67
63 return new Response($this->html, 200); 68 return new Response($this->html, 200);
diff --git a/src/model/entities/Node.php b/src/model/entities/Node.php
index f7af6de..ec5f081 100644
--- a/src/model/entities/Node.php
+++ b/src/model/entities/Node.php
@@ -172,11 +172,7 @@ class Node
172 { 172 {
173 $this->children[] = $child; 173 $this->children[] = $child;
174 174
175 // cas particulier des news: utilise les dates au lieu des positions (les positions existent mais sont ignorées) 175 if(!\Blocks::hasPresentation($this->getName())){ // post_block et news_block ont leurs enfants ordonnés avec ORDER BY
176 if($this->getName() === 'news_block'){
177 $this->sortNews($this->getNodeData()->getChronoOrder() ?? false); // faux = ordre chronologique
178 }
179 else{
180 $this->sortChildren(false); 176 $this->sortChildren(false);
181 } 177 }
182 } 178 }
diff --git a/src/model/entities/NodeData.php b/src/model/entities/NodeData.php
index 0d42f3a..1d7db4c 100644
--- a/src/model/entities/NodeData.php
+++ b/src/model/entities/NodeData.php
@@ -36,6 +36,9 @@ class NodeData
36 #[ORM\Column(type: "integer", nullable: true)] 36 #[ORM\Column(type: "integer", nullable: true)]
37 private ?int $grid_cols_min_width = null; // pour le mode grille 37 private ?int $grid_cols_min_width = null; // pour le mode grille
38 38
39 #[ORM\Column(type: "integer", nullable: true)]
40 private ?int $pagination_limit = null; // pour les post_block et news_block
41
39 // liaison avec table intermédiaire 42 // liaison avec table intermédiaire
40 #[ORM\ManyToMany(targetEntity: Image::class, inversedBy: "node_data")] 43 #[ORM\ManyToMany(targetEntity: Image::class, inversedBy: "node_data")]
41 #[ORM\JoinTable( 44 #[ORM\JoinTable(
@@ -105,6 +108,11 @@ class NodeData
105 { 108 {
106 $this->chrono_order = $reverse_order; 109 $this->chrono_order = $reverse_order;
107 } 110 }
111
112 public function getPaginationLimit(): ?int
113 {
114 return $this->pagination_limit ?? null;
115 }
108 116
109 /*public function setNode(Node $node): void 117 /*public function setNode(Node $node): void
110 { 118 {