From 596ce6f78e37c901d9b4ed464918b0294ba8dd2a Mon Sep 17 00:00:00 2001 From: polo Date: Fri, 10 Oct 2025 17:29:30 +0200 Subject: src/controller/Director.php devient /src/model/Model.php, message d'erreur type de bloc dans modify_block.php --- public/index.php | 2 +- src/controller/ArticleController.php | 42 ++--- src/controller/Director.php | 256 ---------------------------- src/controller/MenuAndPathsController.php | 30 ++-- src/controller/PageManagementController.php | 90 +++++----- src/controller/ViewController.php | 8 +- src/model/Model.php | 254 +++++++++++++++++++++++++++ src/model/Path.php | 2 +- src/router.php | 4 +- src/view/BreadcrumbBuilder.php | 2 +- src/view/FooterBuilder.php | 2 +- src/view/HeadBuilder.php | 4 +- src/view/MainBuilder.php | 2 +- src/view/MenuBuilder.php | 4 +- src/view/NavBuilder.php | 6 +- src/view/NewPageBuilder.php | 2 +- src/view/templates/modify_block.php | 2 +- src/view/templates/modify_page.php | 14 +- 18 files changed, 362 insertions(+), 364 deletions(-) delete mode 100644 src/controller/Director.php create mode 100644 src/model/Model.php diff --git a/public/index.php b/public/index.php index 9caee0a..61fa01f 100644 --- a/public/index.php +++ b/public/index.php @@ -4,7 +4,7 @@ /* plan d'action pour "symfonyfier" le site A - 1/ de vrais contrôleurs: classes et méthodes prenant une requête en entrée et retournant une réponse - (début de séparation contrôleurs et classes métier, exemple: ViewController/Director) + (début de séparation contrôleurs et classes métier, exemple: ViewController/Model) 2/ routeur structuré: méthodes GET et POST, content-type, admin 3/ routeur amélioré: pré-routage avec méthodes HTTP: GET, HEAD, POST, PUT, PATCH, DELETE, etc 4/ réécriture avec les classes Request et Response sans toucher les liens diff --git a/src/controller/ArticleController.php b/src/controller/ArticleController.php index fabd997..06562e7 100644 --- a/src/controller/ArticleController.php +++ b/src/controller/ArticleController.php @@ -16,12 +16,12 @@ class ArticleController if($request->query->has('id') && !empty($request->query->get('id')) && $request->query->has('last_article')){ //var_dump($request->query->get('last_article')); $id = (int)$request->get('id'); // type et nettoie - $director = new Director($entityManager); - $director->findNodeById($id); - $parent_block = $director->getNode(); + $model = new Model($entityManager); + $model->findNodeById($id); + $parent_block = $model->getNode(); if(Blocks::hasPresentation($parent_block->getName())){ - $get_articles_return = $director->getNextArticles($parent_block, $request); + $get_articles_return = $model->getNextArticles($parent_block, $request); $bulk_data = $get_articles_return[0]; if($parent_block->getName() === 'post_block'){ @@ -60,7 +60,7 @@ class ArticleController $id = substr($id, 1); } - $director = new Director($entityManager); + $model = new Model($entityManager); $content = $json['content']; // nettoyage @@ -77,12 +77,12 @@ class ArticleController if($json['id'][0] === 'n') // ici $id est un bloc { $section_id = (int)substr($id, 1); // id du bloc
- if(!$director->findNodeById($section_id)){ // erreur mauvais id + if(!$model->findNodeById($section_id)){ // erreur mauvais id echo json_encode(['success' => false, 'error' => 'article_not_saved, bad id']); die; } - $director->makeSectionNode(); - $node = $director->getNode(); // =
+ $model->makeSectionNode(); + $node = $model->getNode(); // =
if(is_array($content)){ // cas d'une nouvelle "news" if($node->getPage()->getEndOfPath() !== $json['from']){ // erreur mauvais from @@ -118,9 +118,9 @@ class ArticleController // modification article //else{} - if($director->makeArticleNode($id)) // une entrée est trouvée + if($model->makeArticleNode($id)) // une entrée est trouvée { - $node = $director->getArticleNode(); // article + $node = $model->getArticleNode(); // article switch($json['id'][0]){ case 'i': $node->getArticle()->setContent($content); @@ -153,14 +153,14 @@ class ArticleController static public function deleteArticle(EntityManager $entityManager, array $data): Response // $data peut être un $_GET ou du JSON { - $director = new Director($entityManager); - if(!$director->makeArticleNode($data['id'], true)){ + $model = new Model($entityManager); + if(!$model->makeArticleNode($data['id'], true)){ return new Response( '{"success": false, "message": "Erreur: pas d\'article à supprimer"}', Response::HTTP_INTERNAL_SERVER_ERROR); // 500 } - $article = $director->getArticleNode(); - $section = $director->getNode(); + $article = $model->getArticleNode(); + $section = $model->getNode(); $entityManager->remove($article); $section->removeChild($article); @@ -181,10 +181,10 @@ class ArticleController static public function switchPositions(EntityManager $entityManager, array $json): void { - $director = new Director($entityManager); - $director->makeArticleNode($json['id1'], true); - $article1 = $director->getArticleNode(); - $section = $director->getNode(); + $model = new Model($entityManager); + $model->makeArticleNode($json['id1'], true); + $article1 = $model->getArticleNode(); + $section = $model->getNode(); $section->sortChildren(true); // régénère les positions avant inversion $article2 = null; @@ -211,9 +211,9 @@ class ArticleController $id = substr($json['id'], 1); $date = new DateTime($json['date']); - $director = new Director($entityManager); - $director->makeArticleNode($id); - $node = $director->getArticleNode(); + $model = new Model($entityManager); + $model->makeArticleNode($id); + $node = $model->getArticleNode(); $node->getArticle()->setDateTime($date); $entityManager->flush(); diff --git a/src/controller/Director.php b/src/controller/Director.php deleted file mode 100644 index 9c1c6e3..0000000 --- a/src/controller/Director.php +++ /dev/null @@ -1,256 +0,0 @@ - src/model/Model.php serait mieux - -declare(strict_types=1); - -use Doctrine\ORM\EntityManager; -use App\Entity\Page; -use App\Entity\Node; -use Doctrine\ORM\QueryBuilder; -use Symfony\Component\HttpFoundation\Request; - -class Director -{ - private EntityManager $entityManager; - static public Menu $menu_data; // pour NavBuilder - static public ?Path $page_path = null; // pour $current dans NavBuilder et pour BreadcrumbBuilder - private Page $page; - private ?Node $node; - private Node $article; - - public function __construct(EntityManager $entityManager) - { - $this->entityManager = $entityManager; - $this->node = new Node; // instance mère "vide" ne possédant rien d'autre que des enfants - } - - // à déplacer dans Path ou un truc comme ça? - // couper Director en deux classes NodeModel et PageModel? - public function makeMenuAndPaths(): void // lit la table "page" - { - self::$menu_data = new Menu($this->entityManager); - self::$page_path = new Path(); - $this->page = self::$page_path->getLast(); - } - - public function getNode(): Node - { - return $this->node; - } - public function getArticleNode(): Node - { - return $this->article; - } - - // affichage d'une page ordinaire - public function getWholePageData(Request $request): void // lit la table "node" + jointures - { - $id = CURRENT_PAGE === 'article' ? htmlspecialchars($request->query->get('id')) : ''; - - if($id === ''){ // page "normale" - // récupérer tous les noeuds sauf les articles - $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)"; - $bulk_data = $this->entityManager - ->createQuery($dql) - ->setParameter('page', $this->page) - ->getResult(); - - // groupes d'articles triés par bloc, permet de paginer par bloc - foreach($bulk_data as $parent_block){ - if(Blocks::hasPresentation($parent_block->getName())){ // = post_block ou news_block - $bulk_data = array_merge($bulk_data, $this->getNextArticles($parent_block, $request)[0]); - } - } - } - else{ // page "article" - $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page OR n.page IS null OR n.id_node = :id'; - $bulk_data = $this->entityManager - ->createQuery($dql) - ->setParameter('page', $this->page) - ->setParameter('id', $id) - ->getResult(); - } - - $this->makeNodeTree($bulk_data); - } - - // récupération d'articles - public function getNextArticles(Node $parent_block, Request $request): array - { - $qb = $this->entityManager->createQueryBuilder(); - $qb->select('n') - ->from('App\Entity\Node', 'n') - ->where('n.parent = :parent') - ->setParameter('parent', $parent_block); - - if($parent_block->getName() === 'post_block'){ - $qb->orderBy('n.position'); - } - elseif($parent_block->getName() === 'news_block'){ - $qb->join('n.article', 'a'); - if($parent_block->getNodeData()->getChronoOrder() ?? false){ // ordre antichrono par défaut - $qb->orderBy('a.date_time', 'ASC'); - } - else{ - $qb->orderBy('a.date_time', 'DESC'); - } - } - - // pagination - $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD - $this->paginateWithCursor($qb, $parent_block, $request->query->get('last_article')); - $result = $qb->getQuery()->getResult(); - - // il reste des articles à récupérer SI on vient d'en récupérer trop - // ET on gère le cas particulier de $limit <= 0 - $truncated = false; - if(count($result) > $limit && $limit > 0){ // si nb résultat > limit > 0 - $truncated = true; - array_pop($result); // compenser le $limit + 1 dans paginateWithCursor - } - - return [$result, $truncated]; // besoin exceptionnel de retourner deux valeurs - } - - private function paginateWithCursor(QueryBuilder $qb, Node $parent_block, ?string $last_article): void - { - //var_dump($last_article); - $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD - - if($limit > 0){ // si 0 ou moins pas de pagination - // nombres de "pages" d'articles - $nb_pages = $this->getNumberOfPages($parent_block, $limit); - $parent_block->getNodeData()->setNumberOfPages($nb_pages > 1 ? $nb_pages : 1); - - // adaptation de la requête - if($parent_block->getName() === 'post_block'){ - $qb->andWhere('n.position > :last_position') - ->setParameter('last_position', empty($last_article) ? 0 : $last_article) - ->setMaxResults($limit + 1); - } - elseif($parent_block->getName() === 'news_block'){ - $cursor_start = $parent_block->getNodeData()->getChronoOrder() ? '1970-01-01' : '9999-12-31'; - $qb->andWhere($parent_block->getNodeData()->getChronoOrder() ? 'a.date_time > :date_time' : 'a.date_time < :date_time') - ->setParameter('date_time', empty($last_article) ? $cursor_start : $last_article) - ->setMaxResults($limit + 1); - } - } - } - - // le Paginator de doctrine le fait aussi si on décidait de s'en servir - private function getNumberOfPages(Node $parent_block, int $limit): int - { - $dql = 'SELECT COUNT(n.id_node) FROM App\Entity\Node n WHERE n.parent = :parent'; - $nb_articles = $this->entityManager - ->createQuery($dql) - ->setParameter('parent', $parent_block) - ->getSingleScalarResult(); - return (int)ceil($nb_articles / $limit); // que PHP fasse une division non euclidienne (pas comme en C) nous arrange ici - } - - private function makeNodeTree(array $bulk_data): void // $bulk_data = tableau de Node - { - // puis on les range - // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD) - foreach($bulk_data as $node){ - // premier niveau - if($node->getParent() == null){ - $this->node->addChild($node); - - // spécifique page article - if($node->getName() === 'main' && $this->page->getEndOfPath() == 'article'){ - $main = $node; - } - } - // autres niveaux - else{ - $node->getParent()->addChild($node); - - // spécifique page article - if($this->page->getEndOfPath() == 'article'){ - if($node->getName() === 'new'){ - $new = $node; - } - } - } - } - if(isset($new)){ - $main->setAdoptedChild($new); - } - } - - // le basique - public function findNodeById(int $id): bool - { - $this->node = $this->entityManager->find('App\Entity\Node', $id); - return $this->node === null ? false : true; - } - - // récupération d'un article pour modification - public function makeArticleNode(string $id = '', bool $get_section = false): bool - { - if($get_section){ - $dql = 'SELECT n, p FROM App\Entity\Node n LEFT JOIN n.parent p WHERE n.id_node = :id'; - } - else{ - $dql = 'SELECT n FROM App\Entity\Node n WHERE n.id_node = :id'; - } - // n est l'article et p son $parent - $bulk_data = $this->entityManager - ->createQuery($dql) - ->setParameter('id', $id) - ->getResult(); - - if(count($bulk_data) === 0){ - return false; - } - - if($get_section){ - $this->article = $bulk_data[0]; - $this->findNodeById($bulk_data[0]->getParent()->getId()); - $this->makeSectionNode(); - } - else{ - $this->article = $bulk_data[0]; - } - - return true; - } - - // récupération des articles d'un bloc
à la création d'un article - public function makeSectionNode(): bool - { - $bulk_data = $this->entityManager - ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent') - ->setParameter('parent', $this->node) - ->getResult(); - - foreach($bulk_data as $article){ - $this->node->addChild($article); // pas de flush, on ne va pas écrire dans la BDD à chaque nouvelle page - } - return true; - } - - public function findUniqueNodeByName(string $name): void // = unique en BDD, donc sans "page" associée - { - $bulk_data = $this->entityManager - ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.name_node = :name') - ->setParameter('name', $name) - ->getResult(); - $this->node = $bulk_data[0]; - } - - public function findItsChildren(): void - { - $bulk_data = $this->entityManager - ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent AND n.page = :page') - ->setParameter('parent', $this->node) - ->setParameter('page', $this->page) - ->getResult(); - foreach($bulk_data as $child){ - $this->node->addChild($child); - } - } -} diff --git a/src/controller/MenuAndPathsController.php b/src/controller/MenuAndPathsController.php index 3ff7d54..f0553ad 100644 --- a/src/controller/MenuAndPathsController.php +++ b/src/controller/MenuAndPathsController.php @@ -10,8 +10,8 @@ class MenuAndPathsController { static public function newUrlMenuEntry(EntityManager $entityManager): void { - Director::$menu_data = new Menu($entityManager); - $previous_page = Director::$menu_data->findPageById((int)$_POST["location"]); // (int) à cause de declare(strict_types=1); + Model::$menu_data = new Menu($entityManager); + $previous_page = Model::$menu_data->findPageById((int)$_POST["location"]); // (int) à cause de declare(strict_types=1); $parent = $previous_page->getParent(); $url_input = trim($_POST["url_input"]); // faire htmlspecialchars à l'affichage @@ -31,7 +31,7 @@ class MenuAndPathsController // addChild l'ajoute à la fin du tableau "children" puis on trie // 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 if(!$parent){ - $parent = Director::$menu_data; + $parent = Model::$menu_data; } $parent->addChild($page); // true pour réindexer les positions en BDD $parent->reindexPositions(); @@ -63,11 +63,11 @@ class MenuAndPathsController static public function deleteUrlMenuEntry(EntityManager $entityManager): void { - Director::$menu_data = new Menu($entityManager); - $page = Director::$menu_data->findPageById((int)$_POST["delete"]); + Model::$menu_data = new Menu($entityManager); + $page = Model::$menu_data->findPageById((int)$_POST["delete"]); $parent = $page->getParent(); if($parent == null){ - $parent = Director::$menu_data; + $parent = Model::$menu_data; } $parent->removeChild($page); // suppression de $children avant de trier @@ -82,7 +82,7 @@ class MenuAndPathsController static public function MoveOneLevelUp(EntityManager $entityManager, array $json): void { $id = $json['id']; - $page = Director::$menu_data->findPageById((int)$id); + $page = Model::$menu_data->findPageById((int)$id); $parent = $page->getParent(); // peut être null if($parent === null){ @@ -97,9 +97,9 @@ class MenuAndPathsController // 2ème niveau: le parent devient $menu_data, puis null après tri if($parent->getParent() === null){ // connexion dans les deux sens - $page->setParent(Director::$menu_data); // => pour la persistance + $page->setParent(Model::$menu_data); // => pour la persistance - //Director::$menu_data->addChild($page); // => pour sortChildren + //Model::$menu_data->addChild($page); // => pour sortChildren $page->getParent()->addChild($page); // => pour sortChildren $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères $page->setParent(null); @@ -129,11 +129,11 @@ class MenuAndPathsController static public function MoveOneLevelDown(EntityManager $entityManager, array $json): void { $id = $json['id']; - $page = Director::$menu_data->findPageById((int)$id); + $page = Model::$menu_data->findPageById((int)$id); $parent = $page->getParent(); // peut être null if($parent == null){ - $parent = Director::$menu_data; + $parent = Model::$menu_data; } // BDD @@ -166,8 +166,8 @@ class MenuAndPathsController $id2 = $json['id2']; // vérifier qu'ils ont le même parent - $page1 = Director::$menu_data->findPageById((int)$id1); - $page2 = Director::$menu_data->findPageById((int)$id2); + $page1 = Model::$menu_data->findPageById((int)$id1); + $page2 = Model::$menu_data->findPageById((int)$id2); // double le contrôle fait en JS if($page1->getParent() === $page2->getParent()) // comparaison stricte d'objet (même instance du parent?) @@ -176,7 +176,7 @@ class MenuAndPathsController $tmp = $page1->getPosition(); $page1->setPosition($page2->getPosition()); $page2->setPosition($tmp); - Director::$menu_data->sortChildren(true); // modifie tableau children + Model::$menu_data->sortChildren(true); // modifie tableau children $entityManager->flush(); // nouveau menu @@ -194,7 +194,7 @@ class MenuAndPathsController $id = $json['id']; $checked = $json['checked']; - $page = Director::$menu_data->findPageById((int)$id); + $page = Model::$menu_data->findPageById((int)$id); if($page->isHidden() === $checked){ $page->setHidden(!$checked); $entityManager->flush(); diff --git a/src/controller/PageManagementController.php b/src/controller/PageManagementController.php index e6886b1..9dce952 100644 --- a/src/controller/PageManagementController.php +++ b/src/controller/PageManagementController.php @@ -25,16 +25,16 @@ class PageManagementController static public function updatePageMenuPath(EntityManager $entityManager): void { - Director::$menu_data = new Menu($entityManager); - Director::$page_path = new Path(); - $page = Director::$page_path->getLast(); + Model::$menu_data = new Menu($entityManager); + Model::$page_path = new Path(); + $page = Model::$page_path->getLast(); $path = htmlspecialchars($_POST['page_menu_path']); // mise en snake_case: filtre caractères non-alphanumériques, minuscule, doublons d'underscore, trim des underscores $path = trim(preg_replace('/_+/', '_', strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $path))), '_'); $page->setEndOfPath($path); - foreach(Director::$menu_data->getChildren() as $child){ - if($child->getEndOfPath() === Director::$page_path->getArray()[0]->getEndOfPath()){ + foreach(Model::$menu_data->getChildren() as $child){ + if($child->getEndOfPath() === Model::$page_path->getArray()[0]->getEndOfPath()){ $child->fillChildrenPagePath(); // MAJ de $page_path } } @@ -55,10 +55,10 @@ class PageManagementController static public function newPage(EntityManager $entityManager, array $post): void { // titre et chemin - $director = new Director($entityManager); - $director->makeMenuAndPaths(); - //Director::$menu_data = new Menu($entityManager); - $previous_page = Director::$menu_data->findPageById((int)$post["page_location"]); // (int) à cause de declare(strict_types=1); + $model = new Model($entityManager); + $model->makeMenuAndPaths(); + //Model::$menu_data = new Menu($entityManager); + $previous_page = Model::$menu_data->findPageById((int)$post["page_location"]); // (int) à cause de declare(strict_types=1); $parent = $previous_page->getParent(); $page = new Page( @@ -73,7 +73,7 @@ class PageManagementController // addChild l'ajoute à la fin du tableau "children" puis on trie // 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 if($parent == null){ - $parent = Director::$menu_data; + $parent = Model::$menu_data; } $parent->addChild($page); $parent->reindexPositions(); @@ -127,12 +127,12 @@ class PageManagementController /* partie "blocs" */ static public function addBloc(EntityManager $entityManager): void { - $director = new Director($entityManager); - $director->makeMenuAndPaths(); // on a besoin de page_path qui dépend de menu_data - $page = Director::$page_path->getLast(); - $director->findUniqueNodeByName('main'); - $director->findItsChildren(); - $main = $director->getNode(); + $model = new Model($entityManager); + $model->makeMenuAndPaths(); // on a besoin de page_path qui dépend de menu_data + $page = Model::$page_path->getLast(); + $model->findUniqueNodeByName('main'); + $model->findItsChildren(); + $main = $model->getNode(); $position = count($main->getChildren()) + 1; // position dans la fraterie if(!in_array($_POST["bloc_select"], array_keys(Blocks::$blocks), true)) // 3è param: contrôle du type @@ -185,12 +185,12 @@ class PageManagementController static public function deleteBloc(EntityManager $entityManager): void { - $director = new Director($entityManager); - $director->makeMenuAndPaths(); - $director->findUniqueNodeByName('main'); - $director->findItsChildren(); - //$director->findNodeById((int)$_POST['delete_bloc_id']); - $main = $director->getNode(); + $model = new Model($entityManager); + $model->makeMenuAndPaths(); + $model->findUniqueNodeByName('main'); + $model->findItsChildren(); + //$model->findNodeById((int)$_POST['delete_bloc_id']); + $main = $model->getNode(); $bloc = null; foreach($main->getChildren() as $child){ if($child->getId() === (int)$_POST['delete_bloc_id']){ @@ -212,13 +212,13 @@ class PageManagementController static public function renameBloc(EntityManager $entityManager, array $json): void { if(isset($json['bloc_title']) && $json['bloc_title'] !== null && isset($json['bloc_id']) && is_int($json['bloc_id'])){ - $director = new Director($entityManager); - $director->findNodeById($json['bloc_id']); + $model = new Model($entityManager); + $model->findNodeById($json['bloc_id']); // le titre (du JSON en BDD) est récupéré sous forme de tableau, modifié et renvoyé - $data = $director->getNode()->getNodeData()->getData(); + $data = $model->getNode()->getNodeData()->getData(); $data['title'] = htmlspecialchars($json['bloc_title']); - $director->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title'])); + $model->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title'])); $entityManager->flush(); echo json_encode(['success' => true, 'title' => $data['title']]); @@ -232,11 +232,11 @@ class PageManagementController static public function SwitchBlocsPositions(EntityManager $entityManager, array $json): void { if(isset($json['id1']) && is_int($json['id1']) && isset($json['id2']) && is_int($json['id2']) && isset($_GET['page'])){ - $director = new Director($entityManager); - $director->makeMenuAndPaths(); // true pour $director->findItsChildren(); - $director->findUniqueNodeByName('main'); - $director->findItsChildren(); - $main = $director->getNode(); + $model = new Model($entityManager); + $model->makeMenuAndPaths(); // true pour $model->findItsChildren(); + $model->findUniqueNodeByName('main'); + $model->findItsChildren(); + $main = $model->getNode(); $main->sortChildren(true); // régénère les positions avant inversion $bloc1 = null; @@ -271,8 +271,8 @@ class PageManagementController static public function changeArticlesOrder(EntityManager $entityManager, array $json): void { if(isset($json['id']) && isset($json['chrono_order'])){ - $director = new Director($entityManager); - $director->findNodeById($json['id']); + $model = new Model($entityManager); + $model->findNodeById($json['id']); if($json['chrono_order'] === 'chrono'){ $chrono_order = true; @@ -284,7 +284,7 @@ class PageManagementController echo json_encode(['success' => false]); die; } - $director->getNode()->getNodeData()->setChronoOrder($chrono_order); + $model->getNode()->getNodeData()->setChronoOrder($chrono_order); $entityManager->flush(); echo json_encode(['success' => true, 'chrono_order' => $json['chrono_order']]); @@ -298,16 +298,16 @@ class PageManagementController static public function changePresentation(EntityManager $entityManager, array $json): void { if(isset($json['id']) && isset($json['presentation'])){ - $director = new Director($entityManager); - $director->findNodeById($json['id']); + $model = new Model($entityManager); + $model->findNodeById($json['id']); if(in_array($json['presentation'], array_keys(Blocks::$presentations))){ - $director->getNode()->getNodeData()->setPresentation($json['presentation']); + $model->getNode()->getNodeData()->setPresentation($json['presentation']); $entityManager->flush(); $response_data = ['success' => true, 'presentation' => $json['presentation']]; if($json['presentation'] === 'grid'){ - $response_data['cols_min_width'] = $director->getNode()->getNodeData()->getColsMinWidth(); + $response_data['cols_min_width'] = $model->getNode()->getNodeData()->getColsMinWidth(); } echo json_encode($response_data); } @@ -323,9 +323,9 @@ class PageManagementController static public function changeColsMinWidth(EntityManager $entityManager, array $json): void { if(isset($json['id']) && isset($json['cols_min_width'])){ - $director = new Director($entityManager); - $director->findNodeById($json['id']); - $director->getNode()->getNodeData()->setColsMinWidth((int)$json['cols_min_width']); // attention conversion? + $model = new Model($entityManager); + $model->findNodeById($json['id']); + $model->getNode()->getNodeData()->setColsMinWidth((int)$json['cols_min_width']); // attention conversion? $entityManager->flush(); echo json_encode(['success' => true, 'cols_min_width' => $json['cols_min_width']]); @@ -338,10 +338,10 @@ class PageManagementController static public function changePaginationLimit(EntityManager $entityManager, array $json): void { if(isset($json['id']) && isset($json['pagination_limit'])){ - $director = new Director($entityManager); - $director->findNodeById($json['id']); - $old_limit = $director->getNode()->getNodeData()->getPaginationLimit() ?? 12; - $director->getNode()->getNodeData()->setPaginationLimit((int)$json['pagination_limit']); // attention conversion? + $model = new Model($entityManager); + $model->findNodeById($json['id']); + $old_limit = $model->getNode()->getNodeData()->getPaginationLimit() ?? 12; + $model->getNode()->getNodeData()->setPaginationLimit((int)$json['pagination_limit']); // attention conversion? $entityManager->flush(); diff --git a/src/controller/ViewController.php b/src/controller/ViewController.php index feee0a0..0f21118 100644 --- a/src/controller/ViewController.php +++ b/src/controller/ViewController.php @@ -49,10 +49,10 @@ class ViewController extends AbstractBuilder // ViewController est aussi le prem /* 2/ accès au modèle */ - $director = new Director($entityManager); - $director->makeMenuAndPaths(); - $director->getWholePageData($request); - self::$root_node = $director->getNode(); + $model = new Model($entityManager); + $model->makeMenuAndPaths(); + $model->getWholePageData($request); + self::$root_node = $model->getNode(); /* 3/ 2ème contrôle utilisant les données récupérées */ 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 @@ +entityManager = $entityManager; + $this->node = new Node; // instance mère "vide" ne possédant rien d'autre que des enfants + } + + // à déplacer dans Path ou un truc comme ça? + // couper Model en deux classes NodeModel et PageModel? + public function makeMenuAndPaths(): void // lit la table "page" + { + self::$menu_data = new Menu($this->entityManager); + self::$page_path = new Path(); + $this->page = self::$page_path->getLast(); + } + + public function getNode(): Node + { + return $this->node; + } + public function getArticleNode(): Node + { + return $this->article; + } + + // affichage d'une page ordinaire + public function getWholePageData(Request $request): void // lit la table "node" + jointures + { + $id = CURRENT_PAGE === 'article' ? htmlspecialchars($request->query->get('id')) : ''; + + if($id === ''){ // page "normale" + // récupérer tous les noeuds sauf les articles + $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)"; + $bulk_data = $this->entityManager + ->createQuery($dql) + ->setParameter('page', $this->page) + ->getResult(); + + // groupes d'articles triés par bloc, permet de paginer par bloc + foreach($bulk_data as $parent_block){ + if(Blocks::hasPresentation($parent_block->getName())){ // = post_block ou news_block + $bulk_data = array_merge($bulk_data, $this->getNextArticles($parent_block, $request)[0]); + } + } + } + else{ // page "article" + $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page OR n.page IS null OR n.id_node = :id'; + $bulk_data = $this->entityManager + ->createQuery($dql) + ->setParameter('page', $this->page) + ->setParameter('id', $id) + ->getResult(); + } + + $this->makeNodeTree($bulk_data); + } + + // récupération d'articles + public function getNextArticles(Node $parent_block, Request $request): array + { + $qb = $this->entityManager->createQueryBuilder(); + $qb->select('n') + ->from('App\Entity\Node', 'n') + ->where('n.parent = :parent') + ->setParameter('parent', $parent_block); + + if($parent_block->getName() === 'post_block'){ + $qb->orderBy('n.position'); + } + elseif($parent_block->getName() === 'news_block'){ + $qb->join('n.article', 'a'); + if($parent_block->getNodeData()->getChronoOrder() ?? false){ // ordre antichrono par défaut + $qb->orderBy('a.date_time', 'ASC'); + } + else{ + $qb->orderBy('a.date_time', 'DESC'); + } + } + + // pagination + $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD + $this->paginateWithCursor($qb, $parent_block, $request->query->get('last_article')); + $result = $qb->getQuery()->getResult(); + + // il reste des articles à récupérer SI on vient d'en récupérer trop + // ET on gère le cas particulier de $limit <= 0 + $truncated = false; + if(count($result) > $limit && $limit > 0){ // si nb résultat > limit > 0 + $truncated = true; + array_pop($result); // compenser le $limit + 1 dans paginateWithCursor + } + + return [$result, $truncated]; // besoin exceptionnel de retourner deux valeurs + } + + private function paginateWithCursor(QueryBuilder $qb, Node $parent_block, ?string $last_article): void + { + //var_dump($last_article); + $limit = $parent_block->getNodeData()->getPaginationLimit(); // = 12 par défaut si = null en BDD + + if($limit > 0){ // si 0 ou moins pas de pagination + // nombres de "pages" d'articles + $nb_pages = $this->getNumberOfPages($parent_block, $limit); + $parent_block->getNodeData()->setNumberOfPages($nb_pages > 1 ? $nb_pages : 1); + + // adaptation de la requête + if($parent_block->getName() === 'post_block'){ + $qb->andWhere('n.position > :last_position') + ->setParameter('last_position', empty($last_article) ? 0 : $last_article) + ->setMaxResults($limit + 1); + } + elseif($parent_block->getName() === 'news_block'){ + $cursor_start = $parent_block->getNodeData()->getChronoOrder() ? '1970-01-01' : '9999-12-31'; + $qb->andWhere($parent_block->getNodeData()->getChronoOrder() ? 'a.date_time > :date_time' : 'a.date_time < :date_time') + ->setParameter('date_time', empty($last_article) ? $cursor_start : $last_article) + ->setMaxResults($limit + 1); + } + } + } + + // le Paginator de doctrine le fait aussi si on décidait de s'en servir + private function getNumberOfPages(Node $parent_block, int $limit): int + { + $dql = 'SELECT COUNT(n.id_node) FROM App\Entity\Node n WHERE n.parent = :parent'; + $nb_articles = $this->entityManager + ->createQuery($dql) + ->setParameter('parent', $parent_block) + ->getSingleScalarResult(); + return (int)ceil($nb_articles / $limit); // que PHP fasse une division non euclidienne (pas comme en C) nous arrange ici + } + + private function makeNodeTree(array $bulk_data): void // $bulk_data = tableau de Node + { + // puis on les range + // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD) + foreach($bulk_data as $node){ + // premier niveau + if($node->getParent() == null){ + $this->node->addChild($node); + + // spécifique page article + if($node->getName() === 'main' && $this->page->getEndOfPath() == 'article'){ + $main = $node; + } + } + // autres niveaux + else{ + $node->getParent()->addChild($node); + + // spécifique page article + if($this->page->getEndOfPath() == 'article'){ + if($node->getName() === 'new'){ + $new = $node; + } + } + } + } + if(isset($new)){ + $main->setAdoptedChild($new); + } + } + + // le basique + public function findNodeById(int $id): bool + { + $this->node = $this->entityManager->find('App\Entity\Node', $id); + return $this->node === null ? false : true; + } + + // récupération d'un article pour modification + public function makeArticleNode(string $id = '', bool $get_section = false): bool + { + if($get_section){ + $dql = 'SELECT n, p FROM App\Entity\Node n LEFT JOIN n.parent p WHERE n.id_node = :id'; + } + else{ + $dql = 'SELECT n FROM App\Entity\Node n WHERE n.id_node = :id'; + } + // n est l'article et p son $parent + $bulk_data = $this->entityManager + ->createQuery($dql) + ->setParameter('id', $id) + ->getResult(); + + if(count($bulk_data) === 0){ + return false; + } + + if($get_section){ + $this->article = $bulk_data[0]; + $this->findNodeById($bulk_data[0]->getParent()->getId()); + $this->makeSectionNode(); + } + else{ + $this->article = $bulk_data[0]; + } + + return true; + } + + // récupération des articles d'un bloc
à la création d'un article + public function makeSectionNode(): bool + { + $bulk_data = $this->entityManager + ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent') + ->setParameter('parent', $this->node) + ->getResult(); + + foreach($bulk_data as $article){ + $this->node->addChild($article); // pas de flush, on ne va pas écrire dans la BDD à chaque nouvelle page + } + return true; + } + + public function findUniqueNodeByName(string $name): void // = unique en BDD, donc sans "page" associée + { + $bulk_data = $this->entityManager + ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.name_node = :name') + ->setParameter('name', $name) + ->getResult(); + $this->node = $bulk_data[0]; + } + + public function findItsChildren(): void + { + $bulk_data = $this->entityManager + ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent AND n.page = :page') + ->setParameter('parent', $this->node) + ->setParameter('page', $this->page) + ->getResult(); + foreach($bulk_data as $child){ + $this->node->addChild($child); + } + } +} diff --git a/src/model/Path.php b/src/model/Path.php index ad44fd9..bf9653e 100644 --- a/src/model/Path.php +++ b/src/model/Path.php @@ -17,7 +17,7 @@ class Path extends Page $path_array = explode('/', CURRENT_PAGE); try{ // parcourir le menu de haut en bas pour obtenir un ou plusieurs objets Page - $this->findPage(Director::$menu_data, $path_array); // remplit $this->current_page + $this->findPage(Model::$menu_data, $path_array); // remplit $this->current_page } catch(Exception $e){} } diff --git a/src/router.php b/src/router.php index c11a4e0..7459a0d 100644 --- a/src/router.php +++ b/src/router.php @@ -43,7 +43,7 @@ if($request->getMethod() === 'GET'){ } // construction d'une page - $response = (new ViewController)->buildView($entityManager, $request); // utilise Director + $response = (new ViewController)->buildView($entityManager, $request); // utilise Model // parenthèses nécéssaires autour de l'instanciation pour PHP < 8.4 } @@ -146,7 +146,7 @@ elseif($request->getMethod() === 'POST'){ elseif(isset($_GET['menu_edit'])) { // ne suit pas la règle, faire ça dans un contrôleur - Director::$menu_data = new Menu($entityManager); // récupération des données + Model::$menu_data = new Menu($entityManager); // récupération des données // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions if($_GET['menu_edit'] === 'move_one_level_up' && isset($json['id'])){ diff --git a/src/view/BreadcrumbBuilder.php b/src/view/BreadcrumbBuilder.php index c042fa9..2655551 100644 --- a/src/view/BreadcrumbBuilder.php +++ b/src/view/BreadcrumbBuilder.php @@ -15,7 +15,7 @@ class BreadcrumbBuilder extends AbstractBuilder private function breadcrumbHTML(): string { $asset = 'assets/home.svg'; // => BDD? - $breadcrumb_array = Director::$page_path->getArray(); // tableau de Page + $breadcrumb_array = Model::$page_path->getArray(); // tableau de Page $html = ''; $nb_of_entries = count($breadcrumb_array); diff --git a/src/view/FooterBuilder.php b/src/view/FooterBuilder.php index f20dd2e..0a3f55c 100644 --- a/src/view/FooterBuilder.php +++ b/src/view/FooterBuilder.php @@ -57,7 +57,7 @@ class FooterBuilder extends AbstractBuilder { $div_admin = 'logged_out'; $url = new URL(['page' => 'connection', 'from' => CURRENT_PAGE]); - if(Director::$page_path->getLast()->getEndOfPath() === 'article' && isset($_GET['id'])){ + if(Model::$page_path->getLast()->getEndOfPath() === 'article' && isset($_GET['id'])){ $url->addParams(['id' => $_GET['id']]); } $zone_admin = ''; diff --git a/src/view/HeadBuilder.php b/src/view/HeadBuilder.php index b2f3386..ad6e4ba 100644 --- a/src/view/HeadBuilder.php +++ b/src/view/HeadBuilder.php @@ -47,8 +47,8 @@ class HeadBuilder extends AbstractBuilder $js .= '' . "\n"; } - $title = Director::$page_path->getLast()->getPageName(); - $description = Director::$page_path->getLast()->getDescription(); + $title = Model::$page_path->getLast()->getPageName(); + $description = Model::$page_path->getLast()->getDescription(); // favicon foreach($node->getNodeData()->getImages() as $image) diff --git a/src/view/MainBuilder.php b/src/view/MainBuilder.php index d677971..a920eb4 100644 --- a/src/view/MainBuilder.php +++ b/src/view/MainBuilder.php @@ -16,7 +16,7 @@ class MainBuilder extends AbstractBuilder $this->html .= "
\n"; // page article: cas particulier où l'article est greffé sur main - if(Director::$page_path->getLast()->getEndOfPath() === 'article'){ + if(Model::$page_path->getLast()->getEndOfPath() === 'article'){ // pas censé arriver if(!isset($_GET['id'])){ header('Location: ' . new URL); diff --git a/src/view/MenuBuilder.php b/src/view/MenuBuilder.php index 8ea4b8e..12298cf 100644 --- a/src/view/MenuBuilder.php +++ b/src/view/MenuBuilder.php @@ -21,10 +21,10 @@ class MenuBuilder extends AbstractBuilder if(file_exists($viewFile)) { if($_SESSION['admin']){ - $this->unfoldMenu(Director::$menu_data); + $this->unfoldMenu(Model::$menu_data); if($template){ - $this->unfoldOptions(Director::$menu_data); + $this->unfoldOptions(Model::$menu_data); } } else{ diff --git a/src/view/NavBuilder.php b/src/view/NavBuilder.php index 2cbdef9..07c70d1 100644 --- a/src/view/NavBuilder.php +++ b/src/view/NavBuilder.php @@ -14,9 +14,9 @@ class NavBuilder extends AbstractBuilder { $this->html .= ''; } diff --git a/src/view/NewPageBuilder.php b/src/view/NewPageBuilder.php index 2fae6fa..7bf8628 100644 --- a/src/view/NewPageBuilder.php +++ b/src/view/NewPageBuilder.php @@ -25,7 +25,7 @@ class NewPageBuilder extends AbstractBuilder extract($node->getNodeData()->getData()); }*/ - $this->unfoldOptions(Director::$menu_data); + $this->unfoldOptions(Model::$menu_data); ob_start(); require $viewFile; // insertion de $this->html généré par unfoldMenu diff --git a/src/view/templates/modify_block.php b/src/view/templates/modify_block.php index 3620100..75cb218 100644 --- a/src/view/templates/modify_block.php +++ b/src/view/templates/modify_block.php @@ -1,6 +1,6 @@
-
- +
-- cgit v1.2.3