aboutsummaryrefslogtreecommitdiff
path: root/src/Model
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2026-10-23 00:47:32 +0200
committerpolo <ordipolo@gmx.fr>2026-10-23 00:47:32 +0200
commitf27cca08ff786ceff1870147f6d6bad14d71117f (patch)
treed36597a72025313d6faf4ed228755fa267ebe2f6 /src/Model
parentc7309f900ef05bd5cb313110ec159b761af394ec (diff)
downloadcms-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')
-rw-r--r--src/Model/DatabaseSettingUp.php157
-rw-r--r--src/Model/Entity/AppMetadata.php46
-rw-r--r--src/Model/Entity/Article.php94
-rw-r--r--src/Model/Entity/Asset.php68
-rw-r--r--src/Model/Entity/AssetEmployment.php54
-rw-r--r--src/Model/Entity/Email.php131
-rw-r--r--src/Model/Entity/EmailForm.php57
-rw-r--r--src/Model/Entity/Event.php129
-rw-r--r--src/Model/Entity/Image.php89
-rw-r--r--src/Model/Entity/Log.php38
-rw-r--r--src/Model/Entity/Node.php167
-rw-r--r--src/Model/Entity/NodeData.php102
-rw-r--r--src/Model/Entity/Page.php222
-rw-r--r--src/Model/Entity/Presentation.php135
-rw-r--r--src/Model/Entity/User.php67
-rw-r--r--src/Model/EventDTO.php53
-rw-r--r--src/Model/Menu.php44
-rw-r--r--src/Model/Model.php316
-rw-r--r--src/Model/Path.php80
-rw-r--r--src/Model/Position.php52
-rw-r--r--src/Model/doctrine-bootstrap.php34
21 files changed, 2135 insertions, 0 deletions
diff --git a/src/Model/DatabaseSettingUp.php b/src/Model/DatabaseSettingUp.php
new file mode 100644
index 0000000..725eaed
--- /dev/null
+++ b/src/Model/DatabaseSettingUp.php
@@ -0,0 +1,157 @@
1<?php
2// src/Model/DatabaseSettingUp.php
3
4declare(strict_types=1);
5
6namespace App\Model;
7
8use Doctrine\ORM\EntityManager;
9use App\Entity\AppMetadata;
10use App\Entity\Page;
11use App\Entity\Node;
12use App\Entity\NodeData;
13
14/* création d'un site minimal avec une page d'accueil à la toute 1ère visite du site, ne doit surtout pas être exécutée une seconde fois */
15class DatabaseSettingUp
16{
17 static public function run(EntityManager $entityManager): void
18 {
19 if(!self::isFirstRun($entityManager)){
20 return;
21 }
22
23 // la BDD n'est pas vierge, on ne touche à rien
24 if(!self::areTablesEmpty($entityManager)){
25 return;
26 }
27
28 self::fillStartingDatabase($entityManager);
29
30 // empêcher la réutilisation de cette fonction
31 self::preventReinstallation($entityManager);
32
33 // recharger la page?
34 //header('Location: ' . new URL);
35 }
36
37 // protection 1 utilisé à chaque requête
38 static private function isFirstRun(EntityManager $entityManager): bool
39 {
40 $metadata = $entityManager->getRepository(AppMetadata::class)->find('installed');
41 return !$metadata || $metadata->getValue() !== '1';
42 }
43
44 // protection 2, qui vérifie vraiment que les tables concernées sont vides
45 static private function areTablesEmpty(EntityManager $entityManager): bool
46 {
47 $empty = true;
48 $entities = ['Page', 'Node', 'NodeData'];
49 foreach($entities as $entity){
50 $entity = 'App\Entity\\' . $entity; // nécéssaire quand on insère le nom avec une variable
51
52 if($entityManager
53 ->createQuery("SELECT e FROM $entity e")
54 ->setMaxResults(1)
55 ->getOneOrNullResult()){
56 $empty = false;
57 }
58 }
59
60 // cas anormal détecté, on remet en place la clé "installed"
61 if(!$empty){
62 self::preventReinstallation($entityManager);
63 }
64
65 return $empty;
66 }
67
68 static private function fillStartingDatabase(EntityManager $entityManager): void
69 {
70 /* -- table page -- */
71 // paramètres: name_page, end_of_path, reachable, in_menu, hidden, position, parent
72 $accueil = new Page('Accueil', 'accueil', "Page d'accueil", true, true, false, 1, NULL);
73 $article = new Page('Article', 'article', "", true, false, false, NULL, NULL);
74 $connection = new Page('Connexion', 'connection', "Connexion", true, false, false, NULL, NULL);
75 $my_account = new Page('Mon compte', 'user_edit', "Mon compte", true, false, false, NULL, NULL);
76 $menu_paths = new Page("Menu et chemins", 'menu_paths', "Menu et chemins", true, false, false, NULL, NULL);
77 $menu_paths->addCSS('menu');
78 $menu_paths->addJS('menu');
79 $new_page = new Page('Nouvelle page', 'new_page', "Nouvelle page", true, false, false, NULL, NULL);
80 $new_page->addCSS('new_page');
81 $new_page->addJS('new_page');
82 $emails = new Page("Courriels", 'emails', "Consulter les courriels en base de données", true, false, false, NULL, NULL);
83 $emails->addCSS('show_emails');
84 $emails->addJS('form');
85 $maintenance = new Page("Maintenance", 'maintenance', "Opérations de maintenance, installation, sauvegarde, restauration", true, false, false, NULL, NULL);
86 $maintenance->addCSS('maintenance');
87 $maintenance->addJS('maintenance');
88
89 /* -- table node -- */
90 // paramètres: name_node, article_timestamp, attributes, position, parent, page, article
91 $head = new Node('head', 1, NULL, NULL, NULL);
92 $header = new Node('header', 2, NULL, NULL, NULL);
93 $nav = new Node('nav', 1, $header, NULL, NULL);
94 $main = new Node('main', 3, NULL, NULL, NULL);
95 $footer = new Node('footer', 4, NULL, NULL, NULL);
96 $breadcrumb = new Node('breadcrumb', 2, $header, NULL, NULL);
97 $login = new Node('login', 1, $main, $connection, NULL);
98 $user_edit = new Node('user_edit', 1, $main, $my_account, NULL);
99 $bloc_edit_menu = new Node('menu', 1, $main, $menu_paths, NULL);
100 $bloc_new_page = new Node('new_page', 1, $main, $new_page, NULL);
101 $bloc_emails = new Node('show_emails', 1, $main, $emails, NULL);
102 $bloc_maintenance = new Node('maintenance', 1, $main, $maintenance, NULL);
103
104 /* -- table node_data -- */
105 // paramètres: data, node, images
106 $head_data = new NodeData([], $head);
107 $header_data = new NodeData([], $header);
108 $footer_data = new NodeData([], $footer);
109 $emails_data = new NodeData([], $bloc_emails);
110
111 /* -- table page -- */
112 $entityManager->persist($accueil);
113 $entityManager->persist($article);
114 $entityManager->persist($connection);
115 $entityManager->persist($my_account);
116 $entityManager->persist($menu_paths);
117 $entityManager->persist($new_page);
118 $entityManager->persist($emails);
119 $entityManager->persist($maintenance);
120
121 /* -- table node -- */
122 $entityManager->persist($head);
123 $entityManager->persist($header);
124 $entityManager->persist($nav);
125 $entityManager->persist($main);
126 $entityManager->persist($footer);
127 $entityManager->persist($breadcrumb);
128 $entityManager->persist($login);
129 $entityManager->persist($user_edit);
130 $entityManager->persist($bloc_edit_menu);
131 $entityManager->persist($bloc_new_page);
132 $entityManager->persist($bloc_emails);
133 $entityManager->persist($bloc_maintenance);
134
135 /* -- table node_data -- */
136 $entityManager->persist($head_data);
137 $entityManager->persist($header_data);
138 $entityManager->persist($footer_data);
139 $entityManager->persist($emails_data);
140
141 $entityManager->flush();
142 }
143
144 // met en place la protection
145 static private function preventReinstallation(EntityManager $entityManager): void
146 {
147 $metadata = $entityManager->getRepository(AppMetadata::class)->find('installed');
148 if($metadata){
149 $metadata->setValue('1');
150 }
151 else{
152 $metadata = new AppMetadata('installed', '1');
153 $entityManager->persist($metadata);
154 }
155 $entityManager->flush();
156 }
157} \ No newline at end of file
diff --git a/src/Model/Entity/AppMetadata.php b/src/Model/Entity/AppMetadata.php
new file mode 100644
index 0000000..b7d6923
--- /dev/null
+++ b/src/Model/Entity/AppMetadata.php
@@ -0,0 +1,46 @@
1<?php
2// src/Model/Entity/AppMetadata.php
3
4// comme dans AppMode, prévoir d'ajouter des champs "since" et "by" (qui a changé quoi quel jour?)
5
6declare(strict_types=1);
7
8namespace App\Entity;
9
10use Doctrine\ORM\Mapping as ORM;
11
12#[ORM\Entity]
13#[ORM\Table(name: TABLE_PREFIX . "app_metadata")]
14class AppMetadata
15{
16 #[ORM\Id]
17 #[ORM\Column(type: "string", length: 100)]
18 private string $key_name;
19
20 #[ORM\Column(type: "string")]
21 private string $value;
22
23 public function __construct(string $key, string $value)
24 {
25 $this->key_name = $key;
26 $this->value = $value;
27 }
28
29 public function getKey(): string
30 {
31 return $this->key_name;
32 }
33 public function getValue(): string
34 {
35 return $this->value;
36 }
37
38 public function setKey(string $key): void
39 {
40 $this->key_name = $key;
41 }
42 public function setValue(string $value): void
43 {
44 $this->value = $value;
45 }
46} \ No newline at end of file
diff --git a/src/Model/Entity/Article.php b/src/Model/Entity/Article.php
new file mode 100644
index 0000000..588ebd6
--- /dev/null
+++ b/src/Model/Entity/Article.php
@@ -0,0 +1,94 @@
1<?php
2// src/Model/Entity/Article.php
3//
4// entité commune pour les "post" (articles simples) et les "news" (complexes avec titre, aperçu et contenu)
5
6declare(strict_types=1);
7
8namespace App\Entity;
9
10use Doctrine\ORM\Mapping as ORM;
11use Doctrine\Common\Collections\ArrayCollection;
12use Doctrine\Common\Collections\Collection;
13
14#[ORM\Entity]
15#[ORM\Table(name: TABLE_PREFIX . "article")]
16class Article
17{
18 #[ORM\Id]
19 #[ORM\GeneratedValue]
20 #[ORM\Column(type: "integer")]
21 private int $id_article;
22
23 // datetime_immutable permet à la base de toujours gérer cette clé primaire correctement
24 #[ORM\Column(type: 'datetime', options: ['default' => 'CURRENT_TIMESTAMP'], unique: true)]
25 private ?\DateTime $date_time; // le type datetime de doctrine convertit en type \DateTime de PHP
26
27 #[ORM\Column(type: "text")] // "string" => varchar(255) => risque HTML non valide
28 private string $title;
29
30 #[ORM\Column(type: "text")]
31 private string $preview; // une simple textarea
32
33 #[ORM\Column(type: "text")]
34 private string $content; // de l'éditeur html
35
36 #[ORM\ManyToMany(targetEntity: Image::class, inversedBy: "article")] // cascade: ['remove'] = très dangereux!
37 #[ORM\JoinTable(
38 name: TABLE_PREFIX . "article_image",
39 joinColumns: [new ORM\JoinColumn(name: "article_id", referencedColumnName: "id_article", onDelete: "CASCADE")], // onDelete: "CASCADE": très utile
40 inverseJoinColumns: [new ORM\JoinColumn(name: "image_id", referencedColumnName: "id_image", onDelete: "CASCADE")]
41 )]
42 private Collection $images;
43
44 public function __construct(string $content, ?\DateTime $date_time = null, string $title = '', string $preview = '')
45 {
46 $this->date_time = $date_time;
47 $this->title = $title;
48 $this->preview = $preview;
49 $this->content = $content;
50 $this->images = new ArrayCollection(); // initialisation nécessaire
51 }
52
53 public function getDateTime(): \DateTime
54 {
55 return $this->date_time;
56 }
57 public function setDateTime(\DateTime $date_time): void
58 {
59 $this->date_time = $date_time;
60 }
61 public function getTimestamp(): int
62 {
63 return $this->date_time->getTimestamp();
64 }
65 public function getTitle(): string
66 {
67 return $this->title;
68 }
69 public function setTitle(string $title): void
70 {
71 $this->title = $title;
72 }
73 public function getPreview(): string
74 {
75 return $this->preview;
76 }
77 public function setPreview(string $preview): void
78 {
79 $this->preview = $preview;
80 }
81 public function getContent(): string
82 {
83 return $this->content;
84 }
85 public function setContent(string $data): void
86 {
87 $this->content = $data;
88 }
89
90 public function getImages(): Collection
91 {
92 return $this->images;
93 }
94}
diff --git a/src/Model/Entity/Asset.php b/src/Model/Entity/Asset.php
new file mode 100644
index 0000000..51e21fe
--- /dev/null
+++ b/src/Model/Entity/Asset.php
@@ -0,0 +1,68 @@
1<?php
2// src/Model/Entity/Asset.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9use Doctrine\Common\Collections\Collection;
10
11#[ORM\Entity]
12#[ORM\Table(name: TABLE_PREFIX . "asset")]
13class Asset
14{
15 const PATH = 'assets/';
16 const USER_PATH = 'user_data/assets/';
17 // choisir un répertoire du genre /var/www/html/uploads/? ou au moins hors de /src? j'en sais rien
18
19 #[ORM\Id]
20 #[ORM\GeneratedValue]
21 #[ORM\Column(type: "integer")]
22 private int $id_asset;
23
24 #[ORM\Column(type: "string", length: 255)] // nom de fichier modifié avec uniqid (fichiers différents de même nom)
25 private string $file_name;
26
27 #[ORM\Column(type: "string", length: 255, nullable: true)]
28 private string $mime_type; // image/jpeg, image/png, etc
29
30 #[ORM\Column(type: "string", length: 64, unique: true)] // doctrine n'a pas d'équivalent au type CHAR des BDD (on voulait CHAR(64)), c'est pas grave!
31 private string $hash; // pour détecter deux fichiers identiques, même si leurs noms et les métadonnées changent
32
33 #[ORM\OneToMany(mappedBy: 'asset', targetEntity: AssetEmployment::class)]
34 private Collection $asset_employment;
35
36 public function __construct(string $name, string $mime_type, string $hash)
37 {
38 $this->file_name = $name;
39 $this->mime_type = $mime_type;
40 $this->hash = $hash;
41 }
42
43 public function getFileName(): string
44 {
45 return $this->file_name;
46 }
47 public function setFileName(string $name): void
48 {
49 $this->file_name = $name;
50 }
51 public function getMimeType(): string
52 {
53 return $this->mime_type;
54 }
55 public function setMimeType(string $mime_type): void
56 {
57 $this->mime_type = $mime_type;
58 }
59 public function getHash(): string
60 {
61 return $this->hash;
62 }
63
64 public function getAssetEmployments(): Collection
65 {
66 return $this->asset_employment;
67 }
68}
diff --git a/src/Model/Entity/AssetEmployment.php b/src/Model/Entity/AssetEmployment.php
new file mode 100644
index 0000000..e608af0
--- /dev/null
+++ b/src/Model/Entity/AssetEmployment.php
@@ -0,0 +1,54 @@
1<?php
2// src/Model/Entity/NodeDataAsset.php
3//
4// entité intermédiaire 3 colonnes conçue selon le principe "slot <=> ressource unique" (paires node_data/role uniques)
5// doctrine gère mal les clés primaires triples, j'ai donc choisi une clé primaire double node_data_id/role
6
7declare(strict_types=1);
8
9namespace App\Entity;
10
11use Doctrine\ORM\Mapping as ORM;
12
13#[ORM\Entity]
14#[ORM\Table(name: TABLE_PREFIX . 'asset_employment')]
15class AssetEmployment
16{
17 // clé primaire double
18 #[ORM\Id]
19 #[ORM\ManyToOne(targetEntity: NodeData::class, inversedBy: 'asset_employment')]
20 #[ORM\JoinColumn(name: 'node_data_id', referencedColumnName: 'id_node_data', onDelete: 'CASCADE')]
21 private NodeData $node_data;
22
23 #[ORM\Id]
24 #[ORM\Column(type: 'string', length: 50)]
25 private string $role;
26
27 #[ORM\ManyToOne(targetEntity: Asset::class, inversedBy: 'asset_employment')]
28 #[ORM\JoinColumn(name: 'asset_id', referencedColumnName: 'id_asset', onDelete: 'CASCADE')]
29 private Asset $asset;
30
31 public function __construct(NodeData $node_data, Asset $asset, string $role){
32 $this->node_data = $node_data;
33 $this->asset = $asset;
34 $this->role = $role;
35 }
36
37 /*public function getNodeData(): NodeData
38 {
39 return $this->node_data;
40 }*/
41 public function getAsset(): Asset
42 {
43 return $this->asset;
44 }
45 public function setAsset(Asset $asset): self
46 {
47 $this->asset = $asset;
48 return $this;
49 }
50 public function getRole(): string
51 {
52 return $this->role;
53 }
54}
diff --git a/src/Model/Entity/Email.php b/src/Model/Entity/Email.php
new file mode 100644
index 0000000..8ad66fd
--- /dev/null
+++ b/src/Model/Entity/Email.php
@@ -0,0 +1,131 @@
1<?php
2// src/Model/Entity/Email.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9
10#[ORM\Entity]
11#[ORM\Table(name: TABLE_PREFIX . "email")]
12class Email
13{
14 // en mois
15 const DEFAULT_RETENTION_PERIOD = 36; // 3 ans, justification = prospection, durée "glissante", date de suppression remise à jour à chaque nouvel e-mail
16 const DEFAULT_RETENTION_PERIOD_SENSITIVE = 60; // 5 ans pour données sensibles ou litige, durée de preuve légale, durée non glissante
17
18 #[ORM\Id]
19 #[ORM\GeneratedValue]
20 #[ORM\Column(type: "integer")]
21 private int $id_email;
22
23 #[ORM\Column(type: "string", length: 255)]
24 private string $sender_name;
25
26 #[ORM\Column(type: "string", length: 320)]
27 private string $sender_address;
28
29 #[ORM\Column(type: "string", length: 320)]
30 private string $recipient;
31
32 // inutile, objet = 'Message envoyé par ' . $name . ' (' . $email . ') depuis le site web'
33 /*#[ORM\Column(type: "text")]
34 private string $subject;*/
35
36 #[ORM\Column(type: "text")]
37 private string $content;
38
39 #[ORM\Column(type: 'datetime', options: ['default' => 'CURRENT_TIMESTAMP'])]
40 private \DateTime $date_time;
41
42 #[ORM\Column(type: 'boolean')]
43 private bool $is_sensitive; // "sensitive" tout court est un mot réservé
44
45 #[ORM\Column(type: 'datetime', options: ['default' => 'CURRENT_TIMESTAMP'])]
46 private \DateTime $last_contact_date;
47
48 #[ORM\Column(type: 'datetime', nullable: true)]
49 private ?\DateTime $is_sensitive_since;
50
51 #[ORM\ManyToOne(targetEntity: EmailForm::class)]
52 #[ORM\JoinColumn(name: "email_form_id", referencedColumnName: "id_email_form", nullable: true)]
53 private ?EmailForm $email_form;
54
55 public function __construct(string $sender_name, string $sender_address, string $recipient, string $content, EmailForm $email_form, bool $sensitive = false){
56 $this->sender_name = strtolower($sender_name);
57 $this->sender_address = strtolower($sender_address);
58 $this->recipient = strtolower($recipient);
59 $this->content = $content;
60 $this->date_time = new \DateTime;
61 $this->last_contact_date = new \DateTime;
62 $this->email_form = $email_form;
63 $this->makeSensitive($sensitive);
64 }
65
66 public function getId(): int
67 {
68 return $this->id_email;
69 }
70 public function getSenderName(): string
71 {
72 return $this->sender_name;
73 }
74 public function getSenderAddress(): string
75 {
76 return $this->sender_address;
77 }
78 public function getRecipient(): string
79 {
80 return $this->recipient;
81 }
82 public function getContent(): string
83 {
84 return $this->content;
85 }
86 public function getDateTime(): \DateTime
87 {
88 return $this->date_time;
89 }
90 /*public function getLastContactDate(): \DateTime
91 {
92 return $this->last_contact_date;
93 }*/
94 public function isSensitive(): bool
95 {
96 return $this->is_sensitive;
97 }
98 public function isSensitiveSince(): ?\DateTime
99 {
100 return $this->is_sensitive_since;
101 }
102
103 public function makeSensitive(bool $sensitive = true): void
104 {
105 $this->is_sensitive = $sensitive;
106 if($sensitive && $this->is_sensitive_since === null){
107 $this->is_sensitive_since = new \DateTime();
108 }
109 }
110
111 public function updateLastContactDate(): void
112 {
113 $this->last_contact_date = new \DateTime;
114 }
115
116 public function getDeletionDate(): \DateTime // utilise une durée de conservation $period qui est propre au bloc formulaire (à son EmailForm)
117 {
118 // tests appliqués:
119 // => e-mail associé à un formulaire?
120 // => ce formulaire dispose d'une durée de stockage spécifique?
121 // => cette donnée est un entier > 0
122 $key = $this->is_sensitive ? 'retention_period_sensible' : 'retention_period';
123 $period = $this->email_form ? (int)($this->email_form->getData()[$key] ?? null) : null;
124
125 $default = $this->is_sensitive ? self::DEFAULT_RETENTION_PERIOD_SENSITIVE : self::DEFAULT_RETENTION_PERIOD;
126 $period = ($period === null || $period <= 0) ? $default : $period;
127
128 $date = clone ($this->is_sensitive ? $this->is_sensitive_since : $this->last_contact_date); // erreur si "sensible" mais sans date disponible (pas censé arriver)
129 return $date->modify('+ ' . (string)$period . ' month');
130 }
131} \ No newline at end of file
diff --git a/src/Model/Entity/EmailForm.php b/src/Model/Entity/EmailForm.php
new file mode 100644
index 0000000..5c54b86
--- /dev/null
+++ b/src/Model/Entity/EmailForm.php
@@ -0,0 +1,57 @@
1<?php
2// src/Model/Entity/EmailForm.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9
10#[ORM\Entity]
11#[ORM\Table(name: TABLE_PREFIX . "email_form")]
12class EmailForm{
13 #[ORM\Id]
14 #[ORM\GeneratedValue]
15 #[ORM\Column(type: "integer")]
16 private int $id_email_form;
17
18 // inverseBy fait le lien avec $email_form dans Node (qui a "mappedBy")
19 #[ORM\OneToOne(targetEntity: Node::class, inversedBy: "email_form")]
20 #[ORM\JoinColumn(name: "node_id", referencedColumnName: "id_node")]
21 private ?Node $node;
22
23 #[ORM\Column(type: "json")]
24 private array $data;
25
26 public function __construct(array $data, Node $node){
27 $this->data = $data;
28 $this->node = $node;
29 }
30
31 public function getId(): int
32 {
33 return $this->id_email_form;
34 }
35
36 // getData et updateData sont indentiques au code dans NodeData
37 // plutôt qu'une interface, pourquoi pas une classe abstraite? ou peut-être un trait?
38 public function getData(): array
39 {
40 return $this->data;
41 }
42 public function updateData(string $key, string|int|bool|array $value = ''): void
43 {
44 if($value !== ''){
45 $this->data[$key] = $value;
46 }
47 // si $value est vide, supprime la clé
48 elseif(isset($this->data[$key])){
49 unset($this->data[$key]);
50 }
51 }
52
53 public function setNode(?Node $node): void
54 {
55 $this->node = $node;
56 }
57} \ No newline at end of file
diff --git a/src/Model/Entity/Event.php b/src/Model/Entity/Event.php
new file mode 100644
index 0000000..3b81da7
--- /dev/null
+++ b/src/Model/Entity/Event.php
@@ -0,0 +1,129 @@
1<?php
2// src/Model/Entity/Event.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9
10#[ORM\Entity]
11#[ORM\Table(name: TABLE_PREFIX . 'event')]
12class Event
13{
14 #[ORM\Id]
15 #[ORM\GeneratedValue]
16 #[ORM\Column(type: 'integer')]
17 private int $id;
18
19 #[ORM\Column(type: 'string', length: 255)] // type varchar(255)
20 private string $title;
21 // contrôle JS: if(title.length > 255)
22
23 #[ORM\Column(type: 'text')]
24 private string $description = '';
25 // chatgpt: Dans un contexte API/Front comme FullCalendar,
26 // préférer une chaîne vide à une varaible "null" peut être plus pratique,
27 // car ça évite des contrôles côté JS.
28
29 #[ORM\Column(type: 'datetime')] // chatgpt: Doctrine suppose UTC si pas de configuration spécifique
30 private \DateTimeInterface $start; // typage possible avec une interface,
31 //chatgpt: choix \DateTime par défaut, autorise \DateTimeImmutable
32
33 #[ORM\Column(type: 'datetime')]
34 private \DateTimeInterface $end;
35
36 #[ORM\Column(type: 'boolean')]
37 private bool $all_day;
38
39 #[ORM\Column(type: 'string', length: 7, nullable: true)]
40 private ?string $color = null;
41
42 public function __construct(array $json){
43 $this->securedUpdateFromJSON($json);
44 }
45
46 public function securedUpdateFromJSON(array $json): void
47 {
48 $this->title = htmlspecialchars($json['title']);
49 $this->description = htmlspecialchars($json['description']);
50 try{
51 $this->start = new \Datetime($json['start']);
52 $this->end = new \Datetime($json['end']);
53 }
54 catch(\Exception $e){
55 throw new \InvalidArgumentException('Bad date input');
56 }
57 $all_day = filter_var($json['allDay'] ?? null, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
58 if(!is_bool($all_day)){
59 throw new \InvalidArgumentException('Bad checkbox input');
60 }
61 $this->all_day = $all_day;
62 $this->color = isset($json['color']) ? htmlspecialchars($json['color']) : null;
63 }
64
65 public function getId(): int
66 {
67 return $this->id;
68 }
69
70 public function getTitle(): string
71 {
72 return $this->title;
73 }
74 /*public function setTitle(string $title): self
75 {
76 $this->title = $title;
77 return $this;
78 }*/
79
80 public function getDescription(): string
81 {
82 return $this->description;
83 }
84 /*public function setDescription(string $description = ''): self
85 {
86 $this->description = $description;
87 return $this;
88 }*/
89
90 public function getStart(): \DateTimeInterface
91 {
92 return $this->start;
93 }
94 /*public function setStart(\DateTimeInterface $start): self
95 {
96 $this->start = $start;
97 return $this;
98 }*/
99
100 public function getEnd(): \DateTimeInterface
101 {
102 return $this->end;
103 }
104 /*public function setEnd(\DateTimeInterface $end): self
105 {
106 $this->end = $end;
107 return $this;
108 }*/
109
110 public function isAllDay(): bool
111 {
112 return $this->all_day;
113 }
114 /*public function setAllDay(bool $all_day): self
115 {
116 $this->all_day = $all_day;
117 return $this;
118 }*/
119
120 public function getColor(): ?string
121 {
122 return $this->color;
123 }
124 /*public function setColor(?string $color): self
125 {
126 $this->color = $color;
127 return $this;
128 }*/
129}
diff --git a/src/Model/Entity/Image.php b/src/Model/Entity/Image.php
new file mode 100644
index 0000000..06230ce
--- /dev/null
+++ b/src/Model/Entity/Image.php
@@ -0,0 +1,89 @@
1<?php
2// src/Model/Entity/Image.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\Common\Collections\Collection;
9use Doctrine\ORM\Mapping as ORM;
10
11#[ORM\Entity]
12#[ORM\Table(name: TABLE_PREFIX . "image")]
13class Image
14{
15 #[ORM\Id]
16 #[ORM\GeneratedValue]
17 #[ORM\Column(type: "integer")]
18 private int $id_image;
19
20 #[ORM\Column(type: "string", length: 255, unique: true)] // nom d'image UNIQUE
21 private string $file_name;
22
23 // choisir un répertoire du genre /var/www/html/uploads/ de préférence hors de /src
24 #[ORM\Column(type: "string", length: 255, unique: true, nullable: true)]
25 private ?string $file_path;
26
27 #[ORM\Column(type: "string", length: 255, unique: true, nullable: true)]
28 private ?string $file_path_mini;
29
30 #[ORM\Column(type: "string", length: 255, nullable: true)]
31 private string $mime_type; // image/jpeg, image/png, etc
32
33 #[ORM\Column(type: "string", length: 255, nullable: true)]
34 private string $alt; // texte alternatif
35
36 // autre champs optionnels: file_size, date (default current timestamp)
37
38 /* étapes au téléchargement:
39 => Validation du type de fichier : On vérifie que le fichier est bien une image en utilisant le type MIME. On peut aussi vérifier la taille du fichier.
40 => Création d'un répertoire structuré : On génère un chemin dynamique basé sur la date (uploads/2024/12/24/) pour organiser les images.
41 => Génération d'un nom de fichier unique : On utilise uniqid() pour générer un nom unique et éviter les conflits de nom.
42 => Déplacement du fichier sur le serveur : Le fichier est déplacé depuis son emplacement temporaire vers le répertoire uploads/.
43 => Enregistrement dans la base de données : On enregistre les informations de l'image dans la base de données. */
44
45 #[ORM\ManyToMany(targetEntity: Article::class, mappedBy: "images")]
46 private Collection $article;
47
48 public function __construct(string $name, ?string $path, ?string $path_mini, string $mime_type, string $alt)
49 {
50 $this->file_name = $name;
51 $this->file_path = $path;
52 $this->file_path_mini = $path_mini;
53 $this->mime_type = $mime_type;
54 $this->alt = $alt;
55 }
56
57 public function getFileName(): string
58 {
59 return $this->file_name;
60 }
61 public function getFilePath(): string
62 {
63 return $this->file_path;
64 }
65 public function getFilePathMini(): string
66 {
67 return $this->file_path_mini;
68 }
69 public function getAlt(): string
70 {
71 return $this->alt;
72 }
73
74
75 // pour ViewBuilderController?
76 /*public function displayImage($imageId): void
77 {
78 //$imageId = 1; // Exemple d'ID d'image
79 $stmt = $pdo->prepare("SELECT file_path FROM images WHERE id = ?");
80 $stmt->execute([$imageId]);
81 $image = $stmt->fetch();
82
83 if ($image) {
84 echo "<img src='" . $image['file_path'] . "' alt='Image'>";
85 } else {
86 echo "Image non trouvée.";
87 }
88 }*/
89}
diff --git a/src/Model/Entity/Log.php b/src/Model/Entity/Log.php
new file mode 100644
index 0000000..b1cc168
--- /dev/null
+++ b/src/Model/Entity/Log.php
@@ -0,0 +1,38 @@
1<?php
2// src/Model/Entity/Log.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9
10#[ORM\Entity]
11#[ORM\Table(name: TABLE_PREFIX . "log")]
12class Log
13{
14 #[ORM\Id]
15 #[ORM\GeneratedValue]
16 #[ORM\Column(type: "integer")]
17 private int $id_log;
18
19 #[ORM\Column(type: 'datetime', options: ['default' => 'CURRENT_TIMESTAMP'])] // CURRENT_TIMESTAMP "inutile", date générée par PHP
20 private \DateTime $date_time; // type datetime de doctrine <=> type \DateTime de PHP
21
22 #[ORM\Column(type: "boolean")]
23 private bool $success;
24
25 public function __construct(bool $success){
26 $this->date_time = new \DateTime;
27 $this->success = $success;
28 }
29
30 public function getFormatedDate(): string
31 {
32 return $this->date_time->format('d/m/Y à H\hi');
33 }
34 public function getSuccess(): bool
35 {
36 return $this->success;
37 }
38}
diff --git a/src/Model/Entity/Node.php b/src/Model/Entity/Node.php
new file mode 100644
index 0000000..07666c3
--- /dev/null
+++ b/src/Model/Entity/Node.php
@@ -0,0 +1,167 @@
1<?php
2// src/Model/Entity/Node.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9use App\Model\Position;
10
11#[ORM\Entity]
12#[ORM\Table(name: TABLE_PREFIX . "node")]
13class Node
14{
15 use Position;
16
17 #[ORM\Id]
18 #[ORM\GeneratedValue]
19 #[ORM\Column(type: "integer")]
20 private ?int $id_node = null;
21
22 #[ORM\Column(type: "string", length: 255)]
23 private string $name_node;
24
25 #[ORM\Column(type: "integer")]
26 private int $position;
27
28 #[ORM\ManyToOne(targetEntity: self::class)]
29 //#[ORM\ManyToOne(targetEntity: self::class, fetch: 'EAGER')] // fetch: 'eager' désactive le mode fainéant de doctrine
30 #[ORM\JoinColumn(name: "parent_id", referencedColumnName: "id_node", onDelete: "SET NULL", nullable: true)]
31 private ?self $parent = null;
32
33 // un onDelete: "CASCADE" serait logique ici mais dangereux, on pourrait aussi faire en sorte que les noeuds soient récupérables si la page est brutalement supprimée
34 #[ORM\ManyToOne(targetEntity: Page::class)]
35 #[ORM\JoinColumn(name: "page_id", referencedColumnName: "id_page", nullable: true)]
36 private ?Page $page;
37
38 #[ORM\ManyToOne(targetEntity: Article::class, cascade: ['persist'])]
39 #[ORM\JoinColumn(name: "article_id", referencedColumnName: "id_article", onDelete: "CASCADE", nullable: true)] // supprimer le contenu d'un article supprime les noeuds associés, faux dans l'autre sens
40 private ?Article $article = null;
41
42 // propriété non mappée dans la table "node", la jointure est décrite dans NodeData
43 // elle sert à persister ou supprimer des données par cascade
44 // "mappedBy" permet de cibler $node dans l'autre classe, qui elle possède un "inversedBy"
45 #[ORM\OneToOne(targetEntity: NodeData::class, mappedBy: "node", cascade: ['persist', 'remove'])]
46 private ?NodeData $node_data = null;
47
48 #[ORM\OneToOne(targetEntity: EmailForm::class, mappedBy: "node", cascade: ['persist'])] // pas de remove, les e-mails sont associés au EmailForm
49 private ?EmailForm $email_form = null;
50
51 #[ORM\OneToOne(targetEntity: Presentation::class, mappedBy: "node", cascade: ['persist', 'remove'])]
52 private ?Presentation $presentation = null;
53
54 // attributs non destinés à doctrine
55 private array $children = []; // tableau de Node
56 private ?self $adopted = null; // = "new" est un enfant de "main" lorsque la page est "article"
57
58 public function __construct(string $name = '', int $position = 0, ?self $parent = null, ?Page $page = null, ?Article $article = null){
59 $this->name_node = $name;
60 $this->position = $position;
61 $this->parent = $parent;
62 $this->page = $page;
63 $this->article = $article;
64 }
65
66 // pfff...
67 public function getId(): ?int
68 {
69 return $this->id_node;
70 }
71 public function getName(): string
72 {
73 return $this->name_node;
74 }
75 /*public function setName(string $name): void
76 {
77 $this->name_node = $name;
78 }*/
79
80 public function getParent(): ?self
81 {
82 return $this->parent;
83 }
84 /*public function setParent(?self $parent): void
85 {
86 $this->parent = $parent;
87 }*/
88 public function getPosition(): int
89 {
90 return $this->position;
91 }
92 public function setPosition(int $position): void
93 {
94 $this->position = $position;
95 }
96 public function getPage(): Page
97 {
98 return $this->page;
99 }
100 /*public function setPage(Page $page): void
101 {
102 $this->page = $page;
103 }*/
104
105 // utiliser l'interface de NodeData et EmailForm
106 public function getArticle(): Article
107 {
108 return $this->article;
109 }
110 /*public function setArticle(Article $article): void
111 {
112 $this->article = $article;
113 }*/
114
115 // une interface serait cool!
116 // OU possible un "héritage doctrine", faire en sorte que Node soit la mère de NodeData, EmailForm, Article...
117 // une seule instance est matérialisée par plusieurs tables en même temps
118 public function getNodeData(): NodeData|EmailForm|Presentation|null
119 {
120 // pour du polymorphisme (une unique variable $node_data): opter pour l'héritage
121 return match($this->name_node){
122 'form' => $this->email_form,
123 'post_block', 'news_block' => $this->presentation,
124 default => $this->node_data, // inclut 'calendar'
125 };
126 }
127 public function getChildren(): array
128 {
129 return $this->children;
130 }
131 public function getNodeByName(string $name): ?Node
132 {
133 foreach($this->children as $child){
134 if($child->getName() === $name){
135 return $child;
136 }
137 }
138 return null;
139 }
140 public function addChild(self $child): void
141 {
142 $this->children[] = $child;
143
144 if(!Presentation::hasPresentation($this->getName())){ // post_block et news_block ont leurs enfants ordonnés avec ORDER BY
145 $this->sortChildren(false);
146 }
147 }
148 public function removeChild(self $child): void
149 {
150 foreach($this->children as $key => $object){
151 if($object->getId() === $child->getId()){
152 unset($this->children[$key]);
153 }
154 break;
155 }
156 $this->children = array_values($this->children); // réindexer pour supprimer la case vide
157 }
158
159 public function getAdoptedChild(): ?self // peut renvoyer null
160 {
161 return $this->adopted;
162 }
163 public function setAdoptedChild(self $child): void
164 {
165 $this->adopted = $child;
166 }
167}
diff --git a/src/Model/Entity/NodeData.php b/src/Model/Entity/NodeData.php
new file mode 100644
index 0000000..d81628d
--- /dev/null
+++ b/src/Model/Entity/NodeData.php
@@ -0,0 +1,102 @@
1<?php
2// src/Model/Entity/NodeData.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9use Doctrine\Common\Collections\ArrayCollection; // classe
10use Doctrine\Common\Collections\Collection; // interface
11
12#[ORM\Entity]
13#[ORM\Table(name: TABLE_PREFIX . "node_data")]
14class NodeData
15{
16 static array $social_networks = ['globe', 'facebook', 'instagram', 'whatsapp', 'snapchat', 'tiktok', 'linkedin', 'github']; // à completer
17
18 #[ORM\Id]
19 #[ORM\GeneratedValue]
20 #[ORM\Column(type: "integer")]
21 private int $id_node_data;
22
23 // onDelete: "CASCADE" supprime les données si le noeud est supprimé
24 // inverseBy fait le lien avec $node_data dans Node (qui a "mappedBy")
25 #[ORM\OneToOne(targetEntity: Node::class, inversedBy: "node_data")]
26 #[ORM\JoinColumn(name: "node_id", referencedColumnName: "id_node", onDelete: "CASCADE")]
27 private ?Node $node;
28
29 #[ORM\Column(type: "json")]
30 private array $data;
31
32 #[ORM\OneToMany(mappedBy: 'node_data', targetEntity: AssetEmployment::class, cascade: ['persist', 'remove'])]
33 private Collection $asset_employment;
34
35 private array $emails = []; // => noeud "show_emails"
36
37 public function __construct(array $data, Node $node, Collection $asset_employment = new ArrayCollection){
38 $this->data = $data;
39 $this->node = $node;
40 $this->asset_employment = $asset_employment;
41 }
42
43 public function getId(): int
44 {
45 return $this->id_node_data;
46 }
47 public function getData(): array
48 {
49 return $this->data;
50 }
51 /*public function setData(array $data): void // entrée = tableau associatif
52 {
53 $this->data = $data;
54 }*/
55 public function updateData(string $key, string|int|bool|array $value = ''): void
56 {
57 if($value !== ''){
58 $this->data[$key] = $value;
59 }
60 // si $value est vide, supprime la clé
61 elseif(isset($this->data[$key])){
62 unset($this->data[$key]);
63 }
64 }
65
66 public function setNode(?Node $node): void
67 {
68 $this->node = $node;
69 }
70
71 public function getNodeDataAssets(): Collection
72 {
73 return $this->asset_employment;
74 }
75 public function getAssetEmploymentByRole(string $role): ?AssetEmployment
76 {
77 foreach($this->asset_employment as $nda){
78 if($nda->getRole() === $role){
79 return $nda;
80 }
81 }
82 return null;
83 }
84 public function getAssetByRole(string $role): ?Asset
85 {
86 $nda = $this->getAssetEmploymentByRole($role);
87 if($nda === null){
88 return null;
89 }
90 return $nda->getAsset() ?? null;
91 }
92
93 // pour affichage page Courriels
94 public function getEmails(): array // appelée dans ShowEmailsBuilder
95 {
96 return $this->emails;
97 }
98 public function setEmails(array $emails): void // appelée dans Model
99 {
100 $this->emails = $emails;
101 }
102} \ No newline at end of file
diff --git a/src/Model/Entity/Page.php b/src/Model/Entity/Page.php
new file mode 100644
index 0000000..7cca3dc
--- /dev/null
+++ b/src/Model/Entity/Page.php
@@ -0,0 +1,222 @@
1<?php
2// src/Model/Entity/Page.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9use Doctrine\Common\Collections\Collection;
10use Doctrine\Common\Collections\ArrayCollection;
11use App\Model\Position;
12
13#[ORM\Entity]
14#[ORM\Table(name: TABLE_PREFIX . "page")]
15class Page
16{
17 use Position;
18
19 #[ORM\Id]
20 #[ORM\GeneratedValue]
21 #[ORM\Column(type: "integer")]
22 private int $id_page;
23
24 #[ORM\Column(type: "string", length: 255)]
25 private string $name_page;
26
27 #[ORM\Column(type: "string", length: 255)]
28 private string $end_of_path; // morceau d'URL plus exactement
29
30 private string $page_path = '';
31
32 #[ORM\Column(type: "text")]
33 private string $description;
34
35 #[ORM\Column(type: "json", nullable: true)]
36 private ?array $css = null;
37
38 #[ORM\Column(type: "json", nullable: true)]
39 private ?array $js = null;
40
41 static private array $default_css = ['body', 'head', 'nav', 'foot'];
42 static private array $default_js = ['main'];
43
44 #[ORM\Column(type: "boolean")]
45 private bool $reachable;
46
47 #[ORM\Column(type: "boolean")]
48 private bool $in_menu;
49
50 #[ORM\Column(type: "boolean")]
51 private bool $hidden;
52
53 #[ORM\Column(type: "integer", nullable: true)] // null si hors menu
54 private ?int $position;
55
56 #[ORM\ManyToOne(targetEntity: self::class, inversedBy: "children")]
57 #[ORM\JoinColumn(name: "parent_id", referencedColumnName: "id_page", onDelete: "SET NULL", nullable: true)]
58 private ?self $parent = null;
59
60 #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
61 protected Collection $children;
62
63 /*#[ORM\Column(type: "json", nullable: true)]
64 private ?array $metadata = null;*/
65
66 public function __construct(string $name, string $eop, string $description, bool $reachable, bool $in_menu, bool $hidden, ?int $position, ?Page $parent)
67 {
68 $this->name_page = $name;
69 $this->end_of_path = $eop;
70 $this->description = $description;
71 $this->reachable = $reachable;
72 $this->in_menu = $in_menu;
73 $this->hidden = $hidden;
74 $this->position = $position;
75 $this->parent = $parent;
76 $this->children = new ArrayCollection();
77 }
78
79 // getters/setters
80 public function getId(): int
81 {
82 return $this->id_page;
83 }
84 public function getPageName(): string
85 {
86 return $this->name_page;
87 }
88 public function setPageName(string $name): void
89 {
90 $this->name_page = $name;
91 }
92 public function getPagePath(): string
93 {
94 return $this->page_path;
95 }
96 public function setPagePath(string $path):void
97 {
98 $this->page_path = $path;
99 }
100 public function getEndOfPath(): string
101 {
102 return $this->end_of_path;
103 }
104 public function setEndOfPath(string $end_of_path):void
105 {
106 $this->end_of_path = $end_of_path;
107 }
108 public function getDescription(): string
109 {
110 return $this->description;
111 }
112 public function setDescription(string $description): void
113 {
114 $this->description = $description;
115 }
116
117 public function getCSS(): array
118 {
119 return array_merge(self::$default_css, $this->css ?? []);
120 }
121 public function addCSS(string $css): void
122 {
123 if(!in_array($css, $this->css ?? [])){
124 $this->css[] = $css;
125 }
126 }
127 public function removeCSS(string $css): void
128 {
129 // array_diff renvoie une copie du 1er tableau alégée des élements existants aussi dans le 2è, array_values réindexe
130 $this->css = array_values(array_diff($this->css, [$css]));
131 }
132 public function getJS(): array
133 {
134 return array_merge(self::$default_js, $this->js ?? []);
135 //UPDATE `nb_page` SET `js` = NULL WHERE JSON_EQUALS(`js`, '["main"]');
136 }
137 public function addJS(string $js): void
138 {
139 if(!in_array($js, $this->js ?? [])){
140 $this->js[] = $js;
141 }
142 }
143 public function removeJS(string $js): void
144 {
145 $this->js = array_values(array_diff($this->js, [$js]));
146 }
147
148 public function isReachable(): bool
149 {
150 return $this->reachable;
151 }
152 public function isInMenu(): bool
153 {
154 return $this->in_menu;
155 }
156 public function isHidden(): bool
157 {
158 return $this->hidden;
159 }
160 public function setHidden(bool $hidden): void
161 {
162 $this->hidden = $hidden;
163 }
164 public function getPosition(): ?int
165 {
166 return $this->position;
167 }
168 public function setPosition(int $position): void
169 {
170 $this->position = $position;
171 }
172 public function getParent(): ?Page
173 {
174 return $this->parent;
175 }
176 public function setParent(?Page $parent): void
177 {
178 $this->parent = $parent;
179 }
180 public function getChildren(): Collection
181 {
182 return $this->children;
183 }
184
185 // utilisée par $menu_path
186 public function fillChildrenPagePath(string $parent_path = ''): void
187 {
188 $this->page_path = $parent_path != '' ? $parent_path . '/' . $this->end_of_path : $this->end_of_path;
189 foreach($this->getChildren() as $page){
190 $page->fillChildrenPagePath($this->page_path);
191 }
192 }
193
194 public function addChild(self $child): void
195 {
196 $this->children[] = $child;
197 $this->sortChildren(false);
198 }
199 public function removeChild(self $child): void
200 {
201 $this->children->removeElement($child);
202 $this->children = new ArrayCollection(array_values($this->children->toArray())); // réindexer en passant par un tableau
203 $this->sortChildren(false);
204 }
205
206 public function findPageById(int $id): ?Page
207 {
208 $target = null;
209 foreach($this->children as $page){
210 if($page->getId() === $id){
211 return $page;
212 }
213 if(count($page->getChildren()) > 0){
214 $target = $page->findPageById($id);
215 if($target !== null){
216 return $target;
217 }
218 }
219 }
220 return $target;
221 }
222}
diff --git a/src/Model/Entity/Presentation.php b/src/Model/Entity/Presentation.php
new file mode 100644
index 0000000..f5e3502
--- /dev/null
+++ b/src/Model/Entity/Presentation.php
@@ -0,0 +1,135 @@
1<?php
2// src/Model/Entity/Presentation.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9
10#[ORM\Entity]
11#[ORM\Table(name: TABLE_PREFIX . "presentation")]
12class Presentation{
13 #[ORM\Id]
14 #[ORM\GeneratedValue]
15 #[ORM\Column(type: "integer")]
16 private int $id_presentation;
17
18 // inverseBy fait le lien avec $presentation dans Node (qui a "mappedBy")
19 #[ORM\OneToOne(targetEntity: Node::class, inversedBy: "presentation")]
20 #[ORM\JoinColumn(name: "node_id", referencedColumnName: "id_node")]
21 private ?Node $node;
22
23 #[ORM\Column(type: "json")]
24 private array $data;
25
26 #[ORM\Column(type: "string", length: 255, nullable: true)]
27 private ?string $presentation;
28
29 #[ORM\Column(type: "boolean", length: 255, nullable: true)]
30 private ?bool $chrono_order = null;
31
32 #[ORM\Column(type: "integer", nullable: true)]
33 private ?int $grid_cols_min_width = null; // pour le mode grille
34
35 #[ORM\Column(type: "integer", nullable: true)]
36 private ?int $pagination_limit = null; // pour les post_block et news_block
37
38 private int $nb_pages = 1;
39
40 public function __construct(array $data, Node $node
41 //, ?string $presentation = null, ?bool $chrono_order = null
42 ){
43 $this->data = $data;
44 $this->node = $node;
45 /*if(!empty($presentation) && $presentation === 'grid'){
46 $this->grid_cols_min_width = 250;
47 }
48 $this->chrono_order = $chrono_order ?? null;*/
49 }
50
51 /*public function getId(): int
52 {
53 return $this->id_presentation;
54 }*/
55
56 public function setNode(?Node $node): void
57 {
58 $this->node = $node;
59 }
60
61 // un trait pour ça
62 public function getData(): array
63 {
64 return $this->data;
65 }
66 public function updateData(string $key, string|int|bool|array $value = ''): void
67 {
68 if($value !== ''){
69 $this->data[$key] = $value;
70 }
71 // si $value est vide, supprime la clé
72 elseif(isset($this->data[$key])){
73 unset($this->data[$key]);
74 }
75 }
76
77 // spécifique aux blocs contenant des articles
78 public function getPresentation(): ?string
79 {
80 return $this->presentation;
81 }
82 public function setPresentation(string $presentation): void
83 {
84 $this->presentation = $presentation;
85 }
86 public function getColsMinWidth(): int
87 {
88 $default = 320; // pixels
89 return $this->grid_cols_min_width === null ? $default : $this->grid_cols_min_width;
90 }
91 public function setColsMinWidth(int $columns): void
92 {
93 $this->grid_cols_min_width = $columns;
94 }
95 public function getChronoOrder(): bool
96 {
97 return $this->chrono_order ?? false;
98 }
99 public function setChronoOrder(bool $reverse_order): void
100 {
101 $this->chrono_order = $reverse_order;
102 }
103
104 public function getPaginationLimit(): ?int
105 {
106 $default = 12; // si 0 pas de pagination, 12 rend bien avec des grilles de 2, 3 ou 4 colonnes
107 return $this->pagination_limit === null ? $default : $this->pagination_limit;
108 }
109 public function setPaginationLimit(int $pagination_limit): void
110 {
111 $this->pagination_limit = $pagination_limit;
112 }
113 public function getNumberOfPages(): int
114 {
115 return $this->nb_pages;
116 }
117 public function setNumberOfPages(int $nb_pages): void
118 {
119 $this->nb_pages = $nb_pages;
120 }
121
122
123 /* -- blocs et présentations disponibles dans l'application -- */
124 const BLOCKS = ['post_block' => 'Articles libres', 'news_block' => 'Actualités',
125 //'galery' => 'Galerie',
126 'calendar' => 'Calendrier', 'form' => 'Formulaire'
127 ];
128 const PRESENTATIONS = ['fullwidth' => 'Pleine largeur', 'grid' => 'Grille', 'mosaic' => 'Mosaïque'
129 //, 'carousel' => 'Carrousel'
130 ];
131 static public function hasPresentation(string $block): bool
132 {
133 return in_array($block, ['post_block', 'news_block']) ? true : false;
134 }
135} \ No newline at end of file
diff --git a/src/Model/Entity/User.php b/src/Model/Entity/User.php
new file mode 100644
index 0000000..461a5bc
--- /dev/null
+++ b/src/Model/Entity/User.php
@@ -0,0 +1,67 @@
1<?php
2// src/Model/Entity/User.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9
10#[ORM\Entity]
11#[ORM\Table(name: TABLE_PREFIX . "user")]
12class User
13{
14 #[ORM\Id]
15 #[ORM\GeneratedValue]
16 #[ORM\Column(type: "integer")]
17 private int $id_user;
18
19 /*#[ORM\Column(type: "string", length: 255)]
20 private string $name;*/
21
22 #[ORM\Column(type: "string", length: 255, unique: true)] // risque de modifier son mot de passe sans s'apercevoir qu'il fonctionne encore sur un autre compte
23 private string $login;
24
25 #[ORM\Column(type: "string", length: 50)]
26 private string $role;
27
28 #[ORM\Column(type: "string", length: 255)]
29 private string $password;
30
31 public function __construct(string $login, string $role, string $password)
32 {
33 $this->login = $login;
34 $this->role = $role;
35 $this->password = $password;
36 }
37
38 public function getId(): int
39 {
40 return $this->id_user;
41 }
42
43 public function getLogin(): string
44 {
45 return $this->login;
46 }
47 public function setLogin(string $login): void
48 {
49 $this->login = $login;
50 }
51 public function getRole(): string
52 {
53 return $this->role;
54 }
55 public function setRole(string $role): void
56 {
57 $this->role = $role;
58 }
59 public function getPassword(): string
60 {
61 return $this->password;
62 }
63 public function setPassword(string $password): void
64 {
65 $this->password = $password;
66 }
67} \ No newline at end of file
diff --git a/src/Model/EventDTO.php b/src/Model/EventDTO.php
new file mode 100644
index 0000000..b65176c
--- /dev/null
+++ b/src/Model/EventDTO.php
@@ -0,0 +1,53 @@
1<?php
2// src/Model/EventDTO.php
3//
4// classe de données JSONifiable compatible avec fullcalendar
5// servira éventuellement pour l'import/export de fichiers .ics
6
7declare(strict_types=1);
8
9namespace App\Model;
10
11use App\Entity\Event;
12
13class EventDTO
14{
15 public int $id;
16 public string $title;
17 public string $start;
18 public string $end;
19 public bool $allDay;
20 public ?string $color;
21 public string $description;
22
23 public function __construct(Event $event)
24 {
25 $this->id = $event->getId();
26 $this->title = $event->getTitle();
27 $this->description = $event->getDescription() ?? ''; // renvoie $event->getDescription() si existe et ne vaut pas "null"
28 $this->allDay = $event->isAllDay();
29 $this->color = $event->getColor();
30
31 if($this->allDay){
32 $this->start = $event->getStart()->format('Y-m-d');
33 $this->end = $event->getEnd()->format('Y-m-d');
34 }
35 else{
36 $this->start = $event->getStart()->format('Y-m-d\TH:i:s\Z');
37 $this->end = $event->getEnd()->format('Y-m-d\TH:i:s\Z');
38 }
39 }
40
41 public function toArray(): array
42 {
43 return [
44 'id' => $this->id,
45 'title' => $this->title,
46 'description' => $this->description,
47 'start' => $this->start,
48 'end' => $this->end,
49 'allDay' => $this->allDay,
50 'color' => $this->color,
51 ];
52 }
53}
diff --git a/src/Model/Menu.php b/src/Model/Menu.php
new file mode 100644
index 0000000..6b08950
--- /dev/null
+++ b/src/Model/Menu.php
@@ -0,0 +1,44 @@
1<?php
2// src/Model/Menu.php
3
4declare(strict_types=1);
5
6namespace App\Model;
7
8use Doctrine\ORM\EntityManager;
9use Doctrine\Common\Collections\ArrayCollection;
10use App\Entity\Page;
11
12class Menu extends Page
13{
14 private array $other_pages = []; // pages n'apparaissant pas dans le menu
15
16 public function __construct(EntityManager $entityManager){
17 $this->children = new ArrayCollection();
18
19 $bulk_data = $entityManager
20 ->createQuery('SELECT n FROM App\Entity\Page n WHERE n.parent IS null') // :Doctrine\ORM\Query
21 ->getResult(); // :array de Page
22
23 foreach($bulk_data as $first_level_entries){
24 // dans le menu
25 if($first_level_entries->isInMenu()){
26 $this->addChild($first_level_entries);
27 }
28 // autres pages
29 else{
30 // attention, seul le premier élément du chemin est pris en compte
31 $this->other_pages[] = $first_level_entries;
32 }
33 }
34
35 foreach($this->getChildren() as $page){
36 $page->fillChildrenPagePath();
37 }
38 }
39
40 public function getOtherPages(): array
41 {
42 return $this->other_pages;
43 }
44} \ No newline at end of file
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
7declare(strict_types=1);
8
9namespace App\Model;
10
11use Doctrine\ORM\EntityManager;
12use Doctrine\ORM\QueryBuilder;
13use Symfony\Component\HttpFoundation\Request;
14use App\Entity\Page;
15use App\Entity\Node;
16use App\Entity\Presentation;
17use App\Model\Menu;
18use App\Model\Path;
19
20class 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}
diff --git a/src/Model/Path.php b/src/Model/Path.php
new file mode 100644
index 0000000..91eb2ff
--- /dev/null
+++ b/src/Model/Path.php
@@ -0,0 +1,80 @@
1<?php
2// src/Model/Path.php
3//
4// attention, cette classe dépend de src/model/Menu.php
5
6declare(strict_types=1);
7
8namespace App\Model;
9
10use App\Entity\Page;
11use App\Model\Model;
12use App\Model\Menu;
13use App\Service\URL;
14
15class Path extends Page
16{
17 private array $current_page = []; // tableau d'objets Page
18
19 public function __construct()
20 {
21 $path_array = explode('/', CURRENT_PAGE);
22 try{
23 // parcourir le menu de haut en bas pour obtenir un ou plusieurs objets Page
24 $this->findPage(Model::$menu, $path_array); // remplit $this->current_page
25 }
26 catch(\Exception $e){}
27 }
28
29 // produit un tableau de Page en comparant le chemin demandé avec les données dans Menu
30 // succès => une exception est lancée pour sortir des fonctions imbriquées
31 // echec => redirection vers la page erreur 404
32 private function findPage(Page|Menu $menu, array $path_array): void
33 {
34 // recherche dans les autres pages
35 if($menu instanceof Menu){
36 foreach($menu->getOtherPages() as $page){
37 if($path_array[0] === $page->getEndOfPath()){
38 $this->current_page[] = $page;
39 throw new \Exception();
40 }
41 }
42 }
43 // recherche dans le menu
44 foreach($menu->getChildren() as $page){
45 if($path_array[0] === $page->getEndOfPath()){
46 $this->current_page[] = $page;
47 if(count($path_array) > 1){
48 array_shift($path_array); // $this->path_array n'est pas modifié, un tableau PHP est passé à une fonction par copie
49 $this->findPage($page, $path_array);
50 }
51 else{
52 throw new \Exception(); // sortir de tous les findPage() en même temps
53 }
54 }
55 }
56
57 // rien trouvé
58 header('Location: '. new URL(['page' => Model::$menu->getChildren()[0]->getEndOfPath()]));
59 die;
60 }
61
62 public function getString(): string
63 {
64 $path_string = "";
65 foreach($this->current_page as $one_page){
66 $path_string .= $one_page->getEndOfPath() . '/';
67 }
68 return rtrim($path_string, '/');
69 }
70 public function getArray(): array
71 {
72 return $this->current_page;
73 }
74
75 // c'est là qu'on est quoi
76 public function getLast(): Page
77 {
78 return $this->current_page[count($this->current_page) - 1];
79 }
80} \ No newline at end of file
diff --git a/src/Model/Position.php b/src/Model/Position.php
new file mode 100644
index 0000000..7799cdf
--- /dev/null
+++ b/src/Model/Position.php
@@ -0,0 +1,52 @@
1<?php
2// src/Model/Position.php
3//
4// pour Node et Page
5
6declare(strict_types=1);
7
8namespace App\Model;
9
10trait Position
11{
12 // tri par insertion du tableau des enfants
13 public function sortChildren(bool $reindexation = false): void
14 {
15 for($i = 1; $i < count($this->children); $i++)
16 {
17 $tmp = $this->children[$i];
18 $j = $i - 1;
19
20 // Déplacez les éléments du tableau qui sont plus grands que la clé à une position devant leur position actuelle
21 while($j >= 0 && $this->children[$j]->getPosition() > $tmp->getPosition()) {
22 $this->children[$j + 1] = $this->children[$j];
23 $j--;
24 }
25 $this->children[$j + 1] = $tmp;
26 }
27
28 // récursivité (utile dans Menu et chemin)
29 // appel dans Page et dans MenuAndPathController (un tri supplémentaire à faire?)
30 if(self::class === 'App\Entity\Page'){
31 foreach($this->children as $child) {
32 if(count($child->children) > 0) {
33 $child->sortChildren($reindexation);
34 }
35 }
36 }
37
38 if($reindexation){
39 $this->reindexPositions();
40 }
41 }
42
43 // nouvelles positions (tableau $children => BDD)
44 public function reindexPositions(): void
45 {
46 $i = 1;
47 foreach($this->children as $child){
48 $child->setPosition($i);
49 $i++;
50 }
51 }
52} \ No newline at end of file
diff --git a/src/Model/doctrine-bootstrap.php b/src/Model/doctrine-bootstrap.php
new file mode 100644
index 0000000..13db87f
--- /dev/null
+++ b/src/Model/doctrine-bootstrap.php
@@ -0,0 +1,34 @@
1<?php
2// src/Model/doctrine-bootstrap.php
3
4declare(strict_types=1);
5
6use Doctrine\ORM\ORMSetup;
7use Doctrine\DBAL\DriverManager;
8use Doctrine\ORM\EntityManager;
9use App\Service\Config;
10
11//require_once "../vendor/autoload.php";
12
13// Create a simple "default" Doctrine ORM configuration for Attributes
14$config = ORMSetup::createAttributeMetadataConfiguration(
15 //paths: array(__DIR__.'/entities'),
16 paths: array('../src/Model/Entity'),
17 isDevMode: true,
18 // true: cache en mémoire vive
19 // false: utilisation de APCu ou redis ou memcache
20);
21
22// configuring the database connection
23$connection = DriverManager::getConnection([
24 'driver' => Config::$db_driver,
25 'user' => Config::$user,
26 'password' => Config::$password,
27 'host' => Config::$db_host,
28 'dbname' => Config::$database,
29], $config);
30
31// obtaining the entity manager
32$entityManager = new EntityManager($connection, $config);
33
34foreach($entityManager->getMetadataFactory()->getAllMetadata() as $class){} \ No newline at end of file