aboutsummaryrefslogtreecommitdiff
path: root/src/model/Model.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/model/Model.php')
-rw-r--r--src/model/Model.php254
1 files changed, 254 insertions, 0 deletions
diff --git a/src/model/Model.php b/src/model/Model.php
new file mode 100644
index 0000000..ea8ef71
--- /dev/null
+++ b/src/model/Model.php
@@ -0,0 +1,254 @@
1<?php
2// src/model/Model.php
3
4declare(strict_types=1);
5
6use Doctrine\ORM\EntityManager;
7use App\Entity\Page;
8use App\Entity\Node;
9use Doctrine\ORM\QueryBuilder;
10use Symfony\Component\HttpFoundation\Request;
11
12class Model
13{
14 private EntityManager $entityManager;
15 static public Menu $menu_data; // pour NavBuilder
16 static public ?Path $page_path = null; // pour $current dans NavBuilder et pour BreadcrumbBuilder
17 private Page $page;
18 private ?Node $node;
19 private Node $article;
20
21 public function __construct(EntityManager $entityManager)
22 {
23 $this->entityManager = $entityManager;
24 $this->node = new Node; // instance mère "vide" ne possédant rien d'autre que des enfants
25 }
26
27 // à déplacer dans Path ou un truc comme ça?
28 // couper Model en deux classes NodeModel et PageModel?
29 public function makeMenuAndPaths(): void // lit la table "page"
30 {
31 self::$menu_data = new Menu($this->entityManager);
32 self::$page_path = new Path();
33 $this->page = self::$page_path->getLast();
34 }
35
36 public function getNode(): Node
37 {
38 return $this->node;
39 }
40 public function getArticleNode(): Node
41 {
42 return $this->article;
43 }
44
45 // affichage d'une page ordinaire
46 public function getWholePageData(Request $request): void // lit la table "node" + jointures
47 {
48 $id = CURRENT_PAGE === 'article' ? htmlspecialchars($request->query->get('id')) : '';
49
50 if($id === ''){ // page "normale"
51 // récupérer tous les noeuds sauf les articles
52 $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)";
53 $bulk_data = $this->entityManager
54 ->createQuery($dql)
55 ->setParameter('page', $this->page)
56 ->getResult();
57
58 // groupes d'articles triés par bloc, permet de paginer par bloc
59 foreach($bulk_data as $parent_block){
60 if(Blocks::hasPresentation($parent_block->getName())){ // = post_block ou news_block
61 $bulk_data = array_merge($bulk_data, $this->getNextArticles($parent_block, $request)[0]);
62 }
63 }
64 }
65 else{ // page "article"
66 $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page OR n.page IS null OR n.id_node = :id';
67 $bulk_data = $this->entityManager
68 ->createQuery($dql)
69 ->setParameter('page', $this->page)
70 ->setParameter('id', $id)
71 ->getResult();
72 }
73
74 $this->makeNodeTree($bulk_data);
75 }
76
77 // récupération d'articles
78 public function getNextArticles(Node $parent_block, Request $request): array
79 {
80 $qb = $this->entityManager->createQueryBuilder();
81 $qb->select('n')
82 ->from('App\Entity\Node', 'n')
83 ->where('n.parent = :parent')
84 ->setParameter('parent', $parent_block);
85
86 if($parent_block->getName() === 'post_block'){
87 $qb->orderBy('n.position');
88 }
89 elseif($parent_block->getName() === 'news_block'){
90 $qb->join('n.article', 'a');
91 if($parent_block->getNodeData()->getChronoOrder() ?? false){ // ordre antichrono par défaut
92 $qb->orderBy('a.date_time', 'ASC');
93 }
94 else{
95 $qb->orderBy('a.date_time', 'DESC');
96 }
97 }
98
99 // pagination
100 $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD
101 $this->paginateWithCursor($qb, $parent_block, $request->query->get('last_article'));
102 $result = $qb->getQuery()->getResult();
103
104 // il reste des articles à récupérer SI on vient d'en récupérer trop
105 // ET on gère le cas particulier de $limit <= 0
106 $truncated = false;
107 if(count($result) > $limit && $limit > 0){ // si nb résultat > limit > 0
108 $truncated = true;
109 array_pop($result); // compenser le $limit + 1 dans paginateWithCursor
110 }
111
112 return [$result, $truncated]; // besoin exceptionnel de retourner deux valeurs
113 }
114
115 private function paginateWithCursor(QueryBuilder $qb, Node $parent_block, ?string $last_article): void
116 {
117 //var_dump($last_article);
118 $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD
119
120 if($limit > 0){ // si 0 ou moins pas de pagination
121 // nombres de "pages" d'articles
122 $nb_pages = $this->getNumberOfPages($parent_block, $limit);
123 $parent_block->getNodeData()->setNumberOfPages($nb_pages > 1 ? $nb_pages : 1);
124
125 // adaptation de la requête
126 if($parent_block->getName() === 'post_block'){
127 $qb->andWhere('n.position > :last_position')
128 ->setParameter('last_position', empty($last_article) ? 0 : $last_article)
129 ->setMaxResults($limit + 1);
130 }
131 elseif($parent_block->getName() === 'news_block'){
132 $cursor_start = $parent_block->getNodeData()->getChronoOrder() ? '1970-01-01' : '9999-12-31';
133 $qb->andWhere($parent_block->getNodeData()->getChronoOrder() ? 'a.date_time > :date_time' : 'a.date_time < :date_time')
134 ->setParameter('date_time', empty($last_article) ? $cursor_start : $last_article)
135 ->setMaxResults($limit + 1);
136 }
137 }
138 }
139
140 // le Paginator de doctrine le fait aussi si on décidait de s'en servir
141 private function getNumberOfPages(Node $parent_block, int $limit): int
142 {
143 $dql = 'SELECT COUNT(n.id_node) FROM App\Entity\Node n WHERE n.parent = :parent';
144 $nb_articles = $this->entityManager
145 ->createQuery($dql)
146 ->setParameter('parent', $parent_block)
147 ->getSingleScalarResult();
148 return (int)ceil($nb_articles / $limit); // que PHP fasse une division non euclidienne (pas comme en C) nous arrange ici
149 }
150
151 private function makeNodeTree(array $bulk_data): void // $bulk_data = tableau de Node
152 {
153 // puis on les range
154 // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD)
155 foreach($bulk_data as $node){
156 // premier niveau
157 if($node->getParent() == null){
158 $this->node->addChild($node);
159
160 // spécifique page article
161 if($node->getName() === 'main' && $this->page->getEndOfPath() == 'article'){
162 $main = $node;
163 }
164 }
165 // autres niveaux
166 else{
167 $node->getParent()->addChild($node);
168
169 // spécifique page article
170 if($this->page->getEndOfPath() == 'article'){
171 if($node->getName() === 'new'){
172 $new = $node;
173 }
174 }
175 }
176 }
177 if(isset($new)){
178 $main->setAdoptedChild($new);
179 }
180 }
181
182 // le basique
183 public function findNodeById(int $id): bool
184 {
185 $this->node = $this->entityManager->find('App\Entity\Node', $id);
186 return $this->node === null ? false : true;
187 }
188
189 // récupération d'un article pour modification
190 public function makeArticleNode(string $id = '', bool $get_section = false): bool
191 {
192 if($get_section){
193 $dql = 'SELECT n, p FROM App\Entity\Node n LEFT JOIN n.parent p WHERE n.id_node = :id';
194 }
195 else{
196 $dql = 'SELECT n FROM App\Entity\Node n WHERE n.id_node = :id';
197 }
198 // n est l'article et p son $parent
199 $bulk_data = $this->entityManager
200 ->createQuery($dql)
201 ->setParameter('id', $id)
202 ->getResult();
203
204 if(count($bulk_data) === 0){
205 return false;
206 }
207
208 if($get_section){
209 $this->article = $bulk_data[0];
210 $this->findNodeById($bulk_data[0]->getParent()->getId());
211 $this->makeSectionNode();
212 }
213 else{
214 $this->article = $bulk_data[0];
215 }
216
217 return true;
218 }
219
220 // récupération des articles d'un bloc <section> à la création d'un article
221 public function makeSectionNode(): bool
222 {
223 $bulk_data = $this->entityManager
224 ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent')
225 ->setParameter('parent', $this->node)
226 ->getResult();
227
228 foreach($bulk_data as $article){
229 $this->node->addChild($article); // pas de flush, on ne va pas écrire dans la BDD à chaque nouvelle page
230 }
231 return true;
232 }
233
234 public function findUniqueNodeByName(string $name): void // = unique en BDD, donc sans "page" associée
235 {
236 $bulk_data = $this->entityManager
237 ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.name_node = :name')
238 ->setParameter('name', $name)
239 ->getResult();
240 $this->node = $bulk_data[0];
241 }
242
243 public function findItsChildren(): void
244 {
245 $bulk_data = $this->entityManager
246 ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent AND n.page = :page')
247 ->setParameter('parent', $this->node)
248 ->setParameter('page', $this->page)
249 ->getResult();
250 foreach($bulk_data as $child){
251 $this->node->addChild($child);
252 }
253 }
254}