diff options
| author | polo <ordipolo@gmx.fr> | 2026-10-23 00:47:32 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2026-10-23 00:47:32 +0200 |
| commit | f27cca08ff786ceff1870147f6d6bad14d71117f (patch) | |
| tree | d36597a72025313d6faf4ed228755fa267ebe2f6 /src/Model/Model.php | |
| parent | c7309f900ef05bd5cb313110ec159b761af394ec (diff) | |
| download | cms-f27cca08ff786ceff1870147f6d6bad14d71117f.tar.gz cms-f27cca08ff786ceff1870147f6d6bad14d71117f.tar.bz2 cms-f27cca08ff786ceff1870147f6d6bad14d71117f.zip | |
dossiers avec majuscule, namespace pour toutes les classes, autoload psr-4, UserDataService::createZip déplacé dans Backup
Diffstat (limited to 'src/Model/Model.php')
| -rw-r--r-- | src/Model/Model.php | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/src/Model/Model.php b/src/Model/Model.php new file mode 100644 index 0000000..fa8f764 --- /dev/null +++ b/src/Model/Model.php | |||
| @@ -0,0 +1,316 @@ | |||
| 1 | <?php | ||
| 2 | // src/Model/Model.php | ||
| 3 | // | ||
| 4 | // à l'occaz, faire des classes métiers: NodeModel = celle-ci | ||
| 5 | // puis PageModel, puis éventuellement UserModel, EmailModel (le calendrier a déjà EventDTO) | ||
| 6 | |||
| 7 | declare(strict_types=1); | ||
| 8 | |||
| 9 | namespace App\Model; | ||
| 10 | |||
| 11 | use Doctrine\ORM\EntityManager; | ||
| 12 | use Doctrine\ORM\QueryBuilder; | ||
| 13 | use Symfony\Component\HttpFoundation\Request; | ||
| 14 | use App\Entity\Page; | ||
| 15 | use App\Entity\Node; | ||
| 16 | use App\Entity\Presentation; | ||
| 17 | use App\Model\Menu; | ||
| 18 | use App\Model\Path; | ||
| 19 | |||
| 20 | class Model | ||
| 21 | { | ||
| 22 | private EntityManager $entityManager; | ||
| 23 | static public Menu $menu; // pour NavBuilder | ||
| 24 | static public ?Path $page_path = null; // pour $current dans NavBuilder et pour BreadcrumbBuilder | ||
| 25 | private Page $page; | ||
| 26 | private ?Node $node; | ||
| 27 | private Node $article; | ||
| 28 | |||
| 29 | public function __construct(EntityManager $entityManager) | ||
| 30 | { | ||
| 31 | $this->entityManager = $entityManager; | ||
| 32 | $this->node = new Node; // instance mère "vide" ne possédant rien d'autre que des enfants | ||
| 33 | } | ||
| 34 | |||
| 35 | // à déplacer dans Path ou un truc comme ça? | ||
| 36 | // couper Model en deux classes NodeModel et PageModel? | ||
| 37 | public function makeMenuAndPaths(): void // lit la table "page" | ||
| 38 | { | ||
| 39 | self::$menu = new Menu($this->entityManager); | ||
| 40 | self::$page_path = new Path(); | ||
| 41 | $this->page = self::$page_path->getLast(); | ||
| 42 | } | ||
| 43 | |||
| 44 | public function getNode(): Node | ||
| 45 | { | ||
| 46 | return $this->node; | ||
| 47 | } | ||
| 48 | public function getArticleNode(): Node | ||
| 49 | { | ||
| 50 | return $this->article; | ||
| 51 | } | ||
| 52 | |||
| 53 | // affichage d'une page ordinaire | ||
| 54 | public function getWholePageData(Request $request): void // lit la table "node" + jointures | ||
| 55 | { | ||
| 56 | $id = CURRENT_PAGE === 'article' ? htmlspecialchars($request->query->get('id')) : ''; | ||
| 57 | |||
| 58 | if($id === ''){ // page "normale" | ||
| 59 | // récupérer tous les noeuds sauf les articles | ||
| 60 | $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)"; | ||
| 61 | $bulk_data = $this->entityManager | ||
| 62 | ->createQuery($dql) | ||
| 63 | ->setParameter('page', $this->page) | ||
| 64 | ->getResult(); | ||
| 65 | |||
| 66 | foreach($bulk_data as $parent_block){ | ||
| 67 | // groupes d'articles triés par bloc, permet de paginer par bloc | ||
| 68 | if(Presentation::hasPresentation($parent_block->getName())){ // = post_block ou news_block | ||
| 69 | $bulk_data = array_merge($bulk_data, $this->getNextArticles($parent_block, $request)[0]); | ||
| 70 | } | ||
| 71 | |||
| 72 | // emails | ||
| 73 | if($parent_block->getName() === 'show_emails'){ // show_emails = l'afficheur | ||
| 74 | $parent_block->getNodeData()->setEmails($this->getAllEmails()); | ||
| 75 | |||
| 76 | // aller chercher les formulaires à la place (future MAJ?) | ||
| 77 | //$this->getFormsNodeData(); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | else{ // page "article" | ||
| 82 | $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page OR n.page IS null OR n.id_node = :id'; | ||
| 83 | $bulk_data = $this->entityManager | ||
| 84 | ->createQuery($dql) | ||
| 85 | ->setParameter('page', $this->page) | ||
| 86 | ->setParameter('id', $id) | ||
| 87 | ->getResult(); | ||
| 88 | } | ||
| 89 | |||
| 90 | $this->makeNodeTree($bulk_data); | ||
| 91 | } | ||
| 92 | |||
| 93 | // récupération d'articles | ||
| 94 | public function getNextArticles(Node $parent_block, Request $request): array | ||
| 95 | { | ||
| 96 | $qb = $this->entityManager->createQueryBuilder(); | ||
| 97 | $qb->select('n') | ||
| 98 | ->from('App\Entity\Node', 'n') | ||
| 99 | ->where('n.parent = :parent') | ||
| 100 | ->setParameter('parent', $parent_block); | ||
| 101 | |||
| 102 | if($parent_block->getName() === 'post_block'){ | ||
| 103 | $qb->orderBy('n.position'); | ||
| 104 | } | ||
| 105 | elseif($parent_block->getName() === 'news_block'){ | ||
| 106 | $qb->join('n.article', 'a'); | ||
| 107 | if($parent_block->getNodeData()->getChronoOrder() ?? false){ // ordre antichrono par défaut | ||
| 108 | $qb->orderBy('a.date_time', 'ASC'); | ||
| 109 | } | ||
| 110 | else{ | ||
| 111 | $qb->orderBy('a.date_time', 'DESC'); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | // pagination | ||
| 116 | $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD | ||
| 117 | $this->paginateWithCursor($qb, $parent_block, $request->query->get('last_article')); | ||
| 118 | $result = $qb->getQuery()->getResult(); | ||
| 119 | |||
| 120 | // il reste des articles à récupérer SI on vient d'en récupérer trop | ||
| 121 | // ET on gère le cas particulier de $limit <= 0 | ||
| 122 | $truncated = false; | ||
| 123 | if(count($result) > $limit && $limit > 0){ // si nb résultat > limit > 0 | ||
| 124 | $truncated = true; | ||
| 125 | array_pop($result); // compenser le $limit + 1 dans paginateWithCursor | ||
| 126 | } | ||
| 127 | |||
| 128 | return [$result, $truncated]; // besoin exceptionnel de retourner deux valeurs | ||
| 129 | } | ||
| 130 | |||
| 131 | private function paginateWithCursor(QueryBuilder $qb, Node $parent_block, ?string $last_article): void | ||
| 132 | { | ||
| 133 | //var_dump($last_article); | ||
| 134 | $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD | ||
| 135 | |||
| 136 | if($limit > 0){ // si 0 ou moins pas de pagination | ||
| 137 | // nombres de "pages" d'articles | ||
| 138 | $nb_pages = $this->getNumberOfPages($parent_block, $limit); | ||
| 139 | $parent_block->getNodeData()->setNumberOfPages($nb_pages > 1 ? $nb_pages : 1); | ||
| 140 | |||
| 141 | // adaptation de la requête | ||
| 142 | if($parent_block->getName() === 'post_block'){ | ||
| 143 | $qb->andWhere('n.position > :last_position') | ||
| 144 | ->setParameter('last_position', empty($last_article) ? 0 : $last_article) | ||
| 145 | ->setMaxResults($limit + 1); | ||
| 146 | } | ||
| 147 | elseif($parent_block->getName() === 'news_block'){ | ||
| 148 | $cursor_start = $parent_block->getNodeData()->getChronoOrder() ? '1970-01-01' : '9999-12-31'; | ||
| 149 | $qb->andWhere($parent_block->getNodeData()->getChronoOrder() ? 'a.date_time > :date_time' : 'a.date_time < :date_time') | ||
| 150 | ->setParameter('date_time', empty($last_article) ? $cursor_start : $last_article) | ||
| 151 | ->setMaxResults($limit + 1); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | // le Paginator de doctrine le fait aussi si on décidait de s'en servir | ||
| 157 | private function getNumberOfPages(Node $parent_block, int $limit): int | ||
| 158 | { | ||
| 159 | $dql = 'SELECT COUNT(n.id_node) FROM App\Entity\Node n WHERE n.parent = :parent'; | ||
| 160 | $nb_articles = $this->entityManager | ||
| 161 | ->createQuery($dql) | ||
| 162 | ->setParameter('parent', $parent_block) | ||
| 163 | ->getSingleScalarResult(); | ||
| 164 | return (int)ceil($nb_articles / $limit); // que PHP fasse une division non euclidienne (pas comme en C) nous arrange ici | ||
| 165 | } | ||
| 166 | |||
| 167 | private function makeNodeTree(array $bulk_data): void // $bulk_data = tableau de Node | ||
| 168 | { | ||
| 169 | // puis on les range | ||
| 170 | // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD) | ||
| 171 | foreach($bulk_data as $node){ | ||
| 172 | // premier niveau | ||
| 173 | if($node->getParent() == null){ | ||
| 174 | $this->node->addChild($node); | ||
| 175 | |||
| 176 | // spécifique page article | ||
| 177 | if($node->getName() === 'main' && $this->page->getEndOfPath() == 'article'){ | ||
| 178 | $main = $node; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | // autres niveaux | ||
| 182 | else{ | ||
| 183 | $node->getParent()->addChild($node); | ||
| 184 | |||
| 185 | // spécifique page article | ||
| 186 | if($this->page->getEndOfPath() == 'article'){ | ||
| 187 | if($node->getName() === 'new'){ | ||
| 188 | $new = $node; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | if(isset($new)){ | ||
| 194 | $main->setAdoptedChild($new); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | // le basique | ||
| 199 | public function findNodeById(int $id): bool | ||
| 200 | { | ||
| 201 | $this->node = $this->entityManager->find('App\Entity\Node', $id); | ||
| 202 | return $this->node === null ? false : true; | ||
| 203 | } | ||
| 204 | public function findWhateverNode(string $field, string $value): bool | ||
| 205 | { | ||
| 206 | $queryBuilder = $this->entityManager->createQueryBuilder(); | ||
| 207 | $queryBuilder | ||
| 208 | ->select('n') | ||
| 209 | ->from('App\Entity\Node', 'n') | ||
| 210 | ->where("n.$field = :value") // avec le querybuilder, ce truc sale reste sécurisé | ||
| 211 | ->setParameter('value', $value); | ||
| 212 | $result = $queryBuilder->getQuery()->getOneOrNullResult(); | ||
| 213 | |||
| 214 | if($result === null){ | ||
| 215 | return false; | ||
| 216 | } | ||
| 217 | else{ | ||
| 218 | $this->node = $result; | ||
| 219 | return true; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | public function getWhatever(string $class, string $field, string $value): array | ||
| 223 | { | ||
| 224 | // penser au entityManager "repository" | ||
| 225 | $queryBuilder = $this->entityManager->createQueryBuilder(); | ||
| 226 | $queryBuilder | ||
| 227 | ->select('n') | ||
| 228 | ->from($class, 'n') | ||
| 229 | ->where("n.$field = :value") | ||
| 230 | ->setParameter('value', $value); | ||
| 231 | return $queryBuilder->getQuery()->getResult(); | ||
| 232 | } | ||
| 233 | |||
| 234 | // récupération d'un article pour modification | ||
| 235 | public function makeArticleNode(string $id = '', bool $get_section = false): bool | ||
| 236 | { | ||
| 237 | if($get_section){ | ||
| 238 | $dql = 'SELECT n, p FROM App\Entity\Node n LEFT JOIN n.parent p WHERE n.id_node = :id'; | ||
| 239 | } | ||
| 240 | else{ | ||
| 241 | $dql = 'SELECT n FROM App\Entity\Node n WHERE n.id_node = :id'; | ||
| 242 | } | ||
| 243 | // n est l'article et p son $parent | ||
| 244 | $bulk_data = $this->entityManager | ||
| 245 | ->createQuery($dql) | ||
| 246 | ->setParameter('id', $id) | ||
| 247 | ->getResult(); | ||
| 248 | |||
| 249 | if(count($bulk_data) === 0){ | ||
| 250 | return false; | ||
| 251 | } | ||
| 252 | |||
| 253 | if($get_section){ | ||
| 254 | $this->article = $bulk_data[0]; | ||
| 255 | $this->findNodeById($bulk_data[0]->getParent()->getId()); | ||
| 256 | $this->makeSectionNode(); | ||
| 257 | } | ||
| 258 | else{ | ||
| 259 | $this->article = $bulk_data[0]; | ||
| 260 | } | ||
| 261 | |||
| 262 | return true; | ||
| 263 | } | ||
| 264 | |||
| 265 | // récupération des articles d'un bloc <section> à la création d'un article | ||
| 266 | public function makeSectionNode(): bool | ||
| 267 | { | ||
| 268 | $bulk_data = $this->entityManager | ||
| 269 | ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent') | ||
| 270 | ->setParameter('parent', $this->node) | ||
| 271 | ->getResult(); | ||
| 272 | |||
| 273 | foreach($bulk_data as $article){ | ||
| 274 | $this->node->addChild($article); // pas de flush, on ne va pas écrire dans la BDD à chaque nouvelle page | ||
| 275 | } | ||
| 276 | return true; | ||
| 277 | } | ||
| 278 | |||
| 279 | public function findUniqueNodeByName(string $name): void // = unique en BDD, donc sans "page" associée | ||
| 280 | { | ||
| 281 | $bulk_data = $this->entityManager | ||
| 282 | ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.name_node = :name') | ||
| 283 | ->setParameter('name', $name) | ||
| 284 | ->getResult(); | ||
| 285 | $this->node = $bulk_data[0]; | ||
| 286 | } | ||
| 287 | |||
| 288 | public function findItsChildren(): void | ||
| 289 | { | ||
| 290 | $bulk_data = $this->entityManager | ||
| 291 | ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent AND n.page = :page') | ||
| 292 | ->setParameter('parent', $this->node) | ||
| 293 | ->setParameter('page', $this->page) | ||
| 294 | ->getResult(); | ||
| 295 | foreach($bulk_data as $child){ | ||
| 296 | $this->node->addChild($child); | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | private function getAllEmails(): array | ||
| 301 | { | ||
| 302 | $dql = 'SELECT e FROM App\Entity\Email e'; | ||
| 303 | return $this->entityManager | ||
| 304 | ->createQuery($dql) | ||
| 305 | ->getResult(); | ||
| 306 | } | ||
| 307 | /*private function getFormsNodeData(): array | ||
| 308 | { | ||
| 309 | $dql = 'SELECT fd FROM App\Entity\NodeData fd WHERE node.name_node = form'; | ||
| 310 | return $this->entityManager | ||
| 311 | ->createQuery($dql) | ||
| 312 | //->setParameter('page', $this->page) | ||
| 313 | ->getResult(); | ||
| 314 | }*/ | ||
| 315 | //private function getEmailsBySender(string $sender): array | ||
| 316 | } | ||
