diff options
author | polo <ordipolo@gmx.fr> | 2025-10-03 02:28:22 +0200 |
---|---|---|
committer | polo <ordipolo@gmx.fr> | 2025-10-03 02:28:22 +0200 |
commit | d6d7351259e104ab10b5dda3483c281830ce4ff3 (patch) | |
tree | ec555bcbade2ceaa348f3108e585af1273a0c94a | |
parent | f5cb6249dfb339f8e48e49dc131c6efa09c92ecc (diff) | |
download | cms-d6d7351259e104ab10b5dda3483c281830ce4ff3.zip |
pagination partie 1, ordre des articles avec ORDER BY, optimisations dans ViewController
-rw-r--r-- | src/controller/Director.php | 79 | ||||
-rw-r--r-- | src/controller/ViewController.php | 31 | ||||
-rw-r--r-- | src/model/entities/Node.php | 6 | ||||
-rw-r--r-- | src/model/entities/NodeData.php | 8 |
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); | |||
6 | use Doctrine\ORM\EntityManager; | 6 | use Doctrine\ORM\EntityManager; |
7 | use App\Entity\Page; | 7 | use App\Entity\Page; |
8 | use App\Entity\Node; | 8 | use App\Entity\Node; |
9 | //use Doctrine\ORM\QueryBuilder; | ||
10 | use Symfony\Component\HttpFoundation\Request; | ||
9 | 11 | ||
10 | class Director | 12 | class 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 | { |