diff options
| author | polo <ordipolo@gmx.fr> | 2025-10-24 02:27:19 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2025-10-24 02:27:19 +0200 |
| commit | 5311271ae590460b986e3e09edcdc665b73710ca (patch) | |
| tree | f31f6b9602d1607e838a7a4bfe320db9c8d44bb4 /src | |
| parent | f9a9bf1ae4fac9317fd71f0bcb207544b000e6f1 (diff) | |
| download | cms-5311271ae590460b986e3e09edcdc665b73710ca.zip | |
entité pour table intermédiaire à 3 champs entre NodeData et Asset, table Asset repensée
Diffstat (limited to 'src')
| -rw-r--r-- | src/controller/HeadFootController.php | 74 | ||||
| -rw-r--r-- | src/model/Model.php | 11 | ||||
| -rw-r--r-- | src/model/entities/Asset.php | 63 | ||||
| -rw-r--r-- | src/model/entities/Image.php | 3 | ||||
| -rw-r--r-- | src/model/entities/NodeData.php | 69 | ||||
| -rw-r--r-- | src/model/entities/NodeDataAsset.php | 55 | ||||
| -rw-r--r-- | src/view/FooterBuilder.php | 10 | ||||
| -rw-r--r-- | src/view/HeadBuilder.php | 15 | ||||
| -rw-r--r-- | src/view/HeaderBuilder.php | 23 | ||||
| -rw-r--r-- | src/view/templates/footer.php | 2 | ||||
| -rw-r--r-- | src/view/templates/head.php | 4 | ||||
| -rw-r--r-- | src/view/templates/header.php | 2 |
12 files changed, 220 insertions, 111 deletions
diff --git a/src/controller/HeadFootController.php b/src/controller/HeadFootController.php index 0429aac..cf3aed0 100644 --- a/src/controller/HeadFootController.php +++ b/src/controller/HeadFootController.php | |||
| @@ -3,8 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | declare(strict_types=1); | 4 | declare(strict_types=1); |
| 5 | 5 | ||
| 6 | //use App\Entity\Node; | 6 | use App\Entity\NodeDataAsset; |
| 7 | //use App\Entity\NodeData; | ||
| 8 | use App\Entity\Asset; | 7 | use App\Entity\Asset; |
| 9 | use Doctrine\Common\Collections\ArrayCollection; | 8 | use Doctrine\Common\Collections\ArrayCollection; |
| 10 | use Doctrine\ORM\EntityManager; | 9 | use Doctrine\ORM\EntityManager; |
| @@ -38,41 +37,76 @@ class HeadFootController | |||
| 38 | echo json_encode(['success' => false]); | 37 | echo json_encode(['success' => false]); |
| 39 | } | 38 | } |
| 40 | else{ | 39 | else{ |
| 41 | $file = $_FILES['file']; | ||
| 42 | |||
| 43 | if(!is_dir(Asset::USER_PATH)){ | 40 | if(!is_dir(Asset::USER_PATH)){ |
| 44 | mkdir(Asset::USER_PATH, 0700, true); | 41 | mkdir(Asset::USER_PATH, 0700, true); |
| 45 | } | 42 | } |
| 46 | 43 | ||
| 44 | /* -- téléchargement -- */ | ||
| 45 | $file = $_FILES['file']; | ||
| 47 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif', 'ico', 'bmp']; // pas de SVG | 46 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif', 'ico', 'bmp']; // pas de SVG |
| 48 | $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME)); | ||
| 49 | $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); | 47 | $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); |
| 50 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | 48 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ |
| 51 | $extension = 'jpeg'; | 49 | $extension = 'jpeg'; |
| 52 | } | 50 | } |
| 53 | $file_path = uniqid($name . '_') . '.' . $extension; | 51 | $mime_type = mime_content_type($file['tmp_name']); |
| 52 | $hash = hash_file('sha256', $file['tmp_name']); | ||
| 54 | 53 | ||
| 55 | if(ImageUploadController::imagickCleanImage(file_get_contents($file['tmp_name']), Asset::USER_PATH . $file_path, $extension)){ // recréer l’image pour la nettoyer | 54 | /* -- instance d'Asset -- */ |
| 56 | $params_array = explode('_', $request_params); // favicon, header_logo, header_background, footer_logo | 55 | $model = new Model($entityManager); |
| 56 | $result = $model->getWhatever('App\Entity\Asset', 'hash', $hash); | ||
| 57 | 57 | ||
| 58 | $model = new Model($entityManager); | 58 | if(count($result) > 0){ // asset existant trouvé |
| 59 | if($model->findWhateverNode('name_node', $params_array[0])){ | 59 | $asset = $result[0]; |
| 60 | $node_data = $model->getNode()->getNodeData(); | ||
| 61 | $image = new Asset($name, $file_path, mime_content_type($file['tmp_name']), $request_params); | ||
| 62 | $node_data->addAsset($image); | ||
| 63 | 60 | ||
| 64 | $entityManager->persist($image); | 61 | // correction des informations |
| 65 | $entityManager->flush(); | 62 | $name = $asset->getFileName(); // permet à priori de réécrire par dessus le précédent fichier |
| 66 | echo json_encode(['success' => true, 'location' => Asset::USER_PATH . $file_path]); | 63 | //$asset->setFileName($name); |
| 67 | } | 64 | $asset->setMimeType($mime_type); |
| 68 | else{ | ||
| 69 | echo json_encode(['success' => false, 'message' => 'Erreur noeud non trouvé.']); | ||
| 70 | } | ||
| 71 | } | 65 | } |
| 72 | else{ | 66 | else{ |
| 67 | $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME)); | ||
| 68 | $name = uniqid($name . '_') . '.' . $extension; | ||
| 69 | $asset = new Asset($name, $mime_type, $hash); | ||
| 70 | } | ||
| 71 | |||
| 72 | /* -- écriture du fichier sur le disque -- */ | ||
| 73 | if(!ImageUploadController::imagickCleanImage(file_get_contents($file['tmp_name']), Asset::USER_PATH . $name, $extension)){ // recréer l’image pour la nettoyer | ||
| 73 | http_response_code(500); | 74 | http_response_code(500); |
| 74 | echo json_encode(['success' => false, 'message' => 'Erreur image non valide.']); | 75 | echo json_encode(['success' => false, 'message' => 'Erreur image non valide.']); |
| 75 | } | 76 | } |
| 77 | else{ | ||
| 78 | $params_array = explode('_', $request_params); // head_favicon, header_logo, header_background, footer_logo | ||
| 79 | |||
| 80 | /* -- table intermédiaire node_data/asset-- */ | ||
| 81 | if($model->findWhateverNode('name_node', $params_array[0])){ // noeud (head, header ou footer) | ||
| 82 | $node_data = $model->getNode()->getNodeData(); | ||
| 83 | |||
| 84 | // recherche à l'aide du rôle | ||
| 85 | $old_nda = null; | ||
| 86 | foreach($node_data->getNodeDataAssets() as $nda){ | ||
| 87 | if($nda->getRole() === $request_params){ | ||
| 88 | $old_nda = $nda; | ||
| 89 | $old_nda->setAsset($asset); | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | // entrée pas trouvée | ||
| 94 | if($old_nda === null){ | ||
| 95 | $new_nda = new NodeDataAsset($node_data, $asset, $request_params); // $request_params sera le rôle de l'asset | ||
| 96 | $entityManager->persist($new_nda); | ||
| 97 | } | ||
| 98 | |||
| 99 | if(count($result) === 0){ | ||
| 100 | $entityManager->persist($asset); | ||
| 101 | } | ||
| 102 | $entityManager->flush(); | ||
| 103 | echo json_encode(['success' => true, 'location' => Asset::USER_PATH . $name, 'mime_type' => $mime_type]); | ||
| 104 | } | ||
| 105 | else{ | ||
| 106 | http_response_code(500); | ||
| 107 | echo json_encode(['success' => false, 'message' => "Erreur noeud non trouvé, c'est pas du tout normal!"]); | ||
| 108 | } | ||
| 109 | } | ||
| 76 | } | 110 | } |
| 77 | die; | 111 | die; |
| 78 | } | 112 | } |
diff --git a/src/model/Model.php b/src/model/Model.php index 16061e7..68c4c08 100644 --- a/src/model/Model.php +++ b/src/model/Model.php | |||
| @@ -203,6 +203,17 @@ class Model | |||
| 203 | return true; | 203 | return true; |
| 204 | } | 204 | } |
| 205 | } | 205 | } |
| 206 | public function getWhatever(string $class, string $field, string $value): array | ||
| 207 | { | ||
| 208 | // penser au entityManager "repository" | ||
| 209 | $queryBuilder = $this->entityManager->createQueryBuilder(); | ||
| 210 | $queryBuilder | ||
| 211 | ->select('n') | ||
| 212 | ->from($class, 'n') | ||
| 213 | ->where("n.$field = :value") | ||
| 214 | ->setParameter('value', $value); | ||
| 215 | return $queryBuilder->getQuery()->getResult(); | ||
| 216 | } | ||
| 206 | 217 | ||
| 207 | // récupération d'un article pour modification | 218 | // récupération d'un article pour modification |
| 208 | public function makeArticleNode(string $id = '', bool $get_section = false): bool | 219 | public function makeArticleNode(string $id = '', bool $get_section = false): bool |
diff --git a/src/model/entities/Asset.php b/src/model/entities/Asset.php index e359e21..5400db4 100644 --- a/src/model/entities/Asset.php +++ b/src/model/entities/Asset.php | |||
| @@ -6,6 +6,7 @@ declare(strict_types=1); | |||
| 6 | namespace App\Entity; | 6 | namespace App\Entity; |
| 7 | 7 | ||
| 8 | use Doctrine\ORM\Mapping as ORM; | 8 | use Doctrine\ORM\Mapping as ORM; |
| 9 | use Doctrine\Common\Collections\Collection; | ||
| 9 | 10 | ||
| 10 | #[ORM\Entity] | 11 | #[ORM\Entity] |
| 11 | #[ORM\Table(name: TABLE_PREFIX . "asset")] | 12 | #[ORM\Table(name: TABLE_PREFIX . "asset")] |
| @@ -13,71 +14,55 @@ class Asset | |||
| 13 | { | 14 | { |
| 14 | const PATH = 'assets/'; | 15 | const PATH = 'assets/'; |
| 15 | const USER_PATH = 'user_data/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 | ||
| 16 | 18 | ||
| 17 | #[ORM\Id] | 19 | #[ORM\Id] |
| 18 | #[ORM\GeneratedValue] | 20 | #[ORM\GeneratedValue] |
| 19 | #[ORM\Column(type: "integer")] | 21 | #[ORM\Column(type: "integer")] |
| 20 | private int $id_asset; | 22 | private int $id_asset; |
| 21 | 23 | ||
| 22 | #[ORM\Column(type: "string", length: 255, unique: true)] // nom d'image UNIQUE | 24 | #[ORM\Column(type: "string", length: 255)] // nom de fichier modifié avec uniqid (fichiers différents de même nom) |
| 23 | private string $file_name; | 25 | private string $file_name; |
| 24 | 26 | ||
| 25 | // choisir un répertoire du genre /var/www/html/uploads/, au moins hors de /src | ||
| 26 | #[ORM\Column(type: "string", length: 255, unique: true, nullable: true)] | ||
| 27 | private ?string $file_path; | ||
| 28 | |||
| 29 | #[ORM\Column(type: "string", length: 255, nullable: true)] | 27 | #[ORM\Column(type: "string", length: 255, nullable: true)] |
| 30 | private string $mime_type; // image/jpeg, image/png, etc | 28 | private string $mime_type; // image/jpeg, image/png, etc |
| 31 | 29 | ||
| 32 | #[ORM\Column(type: "string", length: 255, nullable: true)] | 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! |
| 33 | private string $alt; // texte alternatif | 31 | private string $hash; // pour détecter deux fichiers identiques, même si leurs noms et les métadonnées changent |
| 34 | |||
| 35 | // autre champs optionnels: file_size, date (default current timestamp) | ||
| 36 | |||
| 37 | /* étapes au téléchargement: | ||
| 38 | => 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. | ||
| 39 | => 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. | ||
| 40 | => 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. | ||
| 41 | => Déplacement du fichier sur le serveur : Le fichier est déplacé depuis son emplacement temporaire vers le répertoire uploads/. | ||
| 42 | => Enregistrement dans la base de données : On enregistre les informations de l'image dans la base de données. */ | ||
| 43 | 32 | ||
| 44 | #[ORM\ManyToMany(targetEntity: NodeData::class, mappedBy: "assets")] | 33 | #[ORM\OneToMany(mappedBy: 'asset', targetEntity: NodeDataAsset::class)] |
| 45 | private $node_data; | 34 | private Collection $nda_collection; |
| 46 | 35 | ||
| 47 | public function __construct(string $name, ?string $path, string $mime_type, string $alt) | 36 | public function __construct(string $name, string $mime_type, string $hash) |
| 48 | { | 37 | { |
| 49 | $this->file_name = $name; | 38 | $this->file_name = $name; |
| 50 | $this->file_path = $path; | ||
| 51 | $this->mime_type = $mime_type; | 39 | $this->mime_type = $mime_type; |
| 52 | $this->alt = $alt; | 40 | $this->hash = $hash; |
| 53 | } | 41 | } |
| 54 | 42 | ||
| 55 | public function getFileName(): string | 43 | public function getFileName(): string |
| 56 | { | 44 | { |
| 57 | return $this->file_name; | 45 | return $this->file_name; |
| 58 | } | 46 | } |
| 59 | public function getFilePath(): string | 47 | public function setFileName(string $name): void |
| 60 | { | 48 | { |
| 61 | return $this->file_path; | 49 | $this->file_name = $name; |
| 62 | } | 50 | } |
| 63 | public function getAlt(): string | 51 | public function getMimeType(): string |
| 64 | { | 52 | { |
| 65 | return $this->alt; | 53 | return $this->mime_type; |
| 66 | } | 54 | } |
| 67 | 55 | public function setMimeType(string $mime_type): void | |
| 68 | |||
| 69 | // pour ViewBuilderController? | ||
| 70 | /*public function displayImage($imageId): void | ||
| 71 | { | 56 | { |
| 72 | //$imageId = 1; // Exemple d'ID d'image | 57 | $this->mime_type = $mime_type; |
| 73 | $stmt = $pdo->prepare("SELECT file_path FROM images WHERE id = ?"); | 58 | } |
| 74 | $stmt->execute([$imageId]); | 59 | public function getHash(): string |
| 75 | $image = $stmt->fetch(); | 60 | { |
| 61 | return $this->hash; | ||
| 62 | } | ||
| 76 | 63 | ||
| 77 | if ($image) { | 64 | public function getNodeDataAssets(): Collection |
| 78 | echo "<img src='" . $image['file_path'] . "' alt='Image'>"; | 65 | { |
| 79 | } else { | 66 | return $this->nda_collection; |
| 80 | echo "Image non trouvée."; | 67 | } |
| 81 | } | ||
| 82 | }*/ | ||
| 83 | } | 68 | } |
diff --git a/src/model/entities/Image.php b/src/model/entities/Image.php index e867a5f..2ee379a 100644 --- a/src/model/entities/Image.php +++ b/src/model/entities/Image.php | |||
| @@ -5,6 +5,7 @@ declare(strict_types=1); | |||
| 5 | 5 | ||
| 6 | namespace App\Entity; | 6 | namespace App\Entity; |
| 7 | 7 | ||
| 8 | use Doctrine\Common\Collections\Collection; | ||
| 8 | use Doctrine\ORM\Mapping as ORM; | 9 | use Doctrine\ORM\Mapping as ORM; |
| 9 | 10 | ||
| 10 | #[ORM\Entity] | 11 | #[ORM\Entity] |
| @@ -42,7 +43,7 @@ class Image | |||
| 42 | => Enregistrement dans la base de données : On enregistre les informations de l'image dans la base de données. */ | 43 | => Enregistrement dans la base de données : On enregistre les informations de l'image dans la base de données. */ |
| 43 | 44 | ||
| 44 | #[ORM\ManyToMany(targetEntity: Article::class, mappedBy: "images")] | 45 | #[ORM\ManyToMany(targetEntity: Article::class, mappedBy: "images")] |
| 45 | private $article; | 46 | private Collection $article; |
| 46 | 47 | ||
| 47 | public function __construct(string $name, ?string $path, ?string $path_mini, string $mime_type, string $alt) | 48 | public function __construct(string $name, ?string $path, ?string $path_mini, string $mime_type, string $alt) |
| 48 | { | 49 | { |
diff --git a/src/model/entities/NodeData.php b/src/model/entities/NodeData.php index 9db866e..47e7208 100644 --- a/src/model/entities/NodeData.php +++ b/src/model/entities/NodeData.php | |||
| @@ -39,21 +39,16 @@ class NodeData | |||
| 39 | #[ORM\Column(type: "integer", nullable: true)] | 39 | #[ORM\Column(type: "integer", nullable: true)] |
| 40 | private ?int $pagination_limit = null; // pour les post_block et news_block | 40 | private ?int $pagination_limit = null; // pour les post_block et news_block |
| 41 | 41 | ||
| 42 | #[ORM\ManyToMany(targetEntity: Asset::class, inversedBy: "node_data")] // cascade: ['remove'] = très dangereux! | 42 | #[ORM\OneToMany(mappedBy: 'node_data', targetEntity: NodeDataAsset::class, cascade: ['persist', 'remove'])] |
| 43 | #[ORM\JoinTable( | 43 | private Collection $nda_collection; |
| 44 | name: TABLE_PREFIX . "nodedata_asset", | ||
| 45 | joinColumns: [new ORM\JoinColumn(name: "node_data_id", referencedColumnName: "id_node_data", onDelete: "CASCADE")], // onDelete: "CASCADE": très utile | ||
| 46 | inverseJoinColumns: [new ORM\JoinColumn(name: "asset_id", referencedColumnName: "id_asset", onDelete: "CASCADE")] | ||
| 47 | )] | ||
| 48 | private Collection $assets; | ||
| 49 | 44 | ||
| 50 | private int $nb_pages = 1; | 45 | private int $nb_pages = 1; |
| 51 | 46 | ||
| 52 | public function __construct(array $data, Node $node, Collection $assets = new ArrayCollection, ?string $presentation = null, ?bool $chrono_order = null) | 47 | public function __construct(array $data, Node $node, Collection $nda_collection = new ArrayCollection, ?string $presentation = null, ?bool $chrono_order = null) |
| 53 | { | 48 | { |
| 54 | $this->data = $data; | 49 | $this->data = $data; |
| 55 | $this->node = $node; | 50 | $this->node = $node; |
| 56 | $this->assets = $assets; | 51 | $this->nda_collection = $nda_collection; |
| 57 | if(!empty($presentation) && $presentation === 'grid'){ | 52 | if(!empty($presentation) && $presentation === 'grid'){ |
| 58 | $this->grid_cols_min_width = 250; | 53 | $this->grid_cols_min_width = 250; |
| 59 | } | 54 | } |
| @@ -132,22 +127,54 @@ class NodeData | |||
| 132 | { | 127 | { |
| 133 | $this->node = $node; | 128 | $this->node = $node; |
| 134 | }*/ | 129 | }*/ |
| 135 | public function getAssets(): Collection | 130 | |
| 131 | |||
| 132 | public function getNodeDataAssets(): Collection | ||
| 136 | { | 133 | { |
| 137 | return $this->assets; | 134 | return $this->nda_collection; |
| 138 | } | 135 | } |
| 139 | public function addAsset(Asset $asset): void | 136 | public function getNodeDataAssetByRole(string $role): ?NodeDataAsset |
| 140 | { | 137 | { |
| 141 | if(!$this->assets->contains($asset)){ | 138 | foreach($this->nda_collection as $nda){ |
| 142 | $this->assets->add($asset); | 139 | if($nda->getRole() === $role){ |
| 143 | //$asset->addNodeData($this); // autre sens | 140 | return $nda; |
| 141 | } | ||
| 144 | } | 142 | } |
| 143 | return null; | ||
| 145 | } | 144 | } |
| 146 | public function removeAsset(Asset $asset): void | 145 | public function getAssetByRole(string $role): ?Asset |
| 147 | { | 146 | { |
| 148 | $this->assets->removeElement($asset); | 147 | $nda = $this->getNodeDataAssetByRole($role); |
| 149 | /*if($this->assets->removeElement($asset)){ // autre sens | 148 | if($nda === null){ |
| 150 | $asset->removeNodeData($this); | 149 | return null; |
| 151 | }*/ | 150 | } |
| 151 | return $nda->getAsset() ?? null; | ||
| 152 | } | 152 | } |
| 153 | } | 153 | /*public function addNodeDataAsset(NodeDataAsset $nda): self |
| 154 | { | ||
| 155 | if(!$this->nda_collection->contains($nda)){ // sécurité contrainte UNIQUE | ||
| 156 | $this->nda_collection->add($nda); | ||
| 157 | } | ||
| 158 | return $this; | ||
| 159 | }*/ | ||
| 160 | /*public function removeNodeDataAsset(NodeDataAsset $nda): self // inutile on peut faire: $node_data->getNodeDataAssets()->removeElement($nda); | ||
| 161 | { | ||
| 162 | $this->nda_collection->removeElement($nda); | ||
| 163 | // pas de synchro dans NodeDataAsset, les champs de cette table ne sont pas nullables | ||
| 164 | return $this; | ||
| 165 | }*/ | ||
| 166 | |||
| 167 | // LE setter, sélectionne l'asset à utiliser en remplaçant l'entrée dans NodeDataAsset en fonction du rôle | ||
| 168 | // à mettre théoriquement dans une classe metier dans "service" | ||
| 169 | /*public function replaceAssetForRole(string $role, Asset $asset): void | ||
| 170 | { | ||
| 171 | foreach($this->nda_collection as $nda){ | ||
| 172 | if($nda->getRole() === $role){ | ||
| 173 | $this->removeNodeDataAsset($nda); | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | $this->new_nda = new NodeDataAsset($this, $asset, $role); | ||
| 178 | $this->addNodeDataAsset($this->new_nda); | ||
| 179 | }*/ | ||
| 180 | } \ No newline at end of file | ||
diff --git a/src/model/entities/NodeDataAsset.php b/src/model/entities/NodeDataAsset.php new file mode 100644 index 0000000..7f7008e --- /dev/null +++ b/src/model/entities/NodeDataAsset.php | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | <?php | ||
| 2 | // src/model/entities/NodeDataAsset.php | ||
| 3 | // | ||
| 4 | // entité intermédiaire avec 3 colonnes | ||
| 5 | |||
| 6 | declare(strict_types=1); | ||
| 7 | |||
| 8 | namespace App\Entity; | ||
| 9 | |||
| 10 | use Doctrine\ORM\Mapping as ORM; | ||
| 11 | |||
| 12 | #[ORM\Entity] | ||
| 13 | #[ORM\Table(name: TABLE_PREFIX . 'nodedata_asset')] | ||
| 14 | #[ORM\UniqueConstraint(name: 'unique_role_per_node', columns: ['node_data_id', 'role'])] // un rôle UNIQUE pour chaque node_data_id, excellent! | ||
| 15 | class NodeDataAsset | ||
| 16 | { | ||
| 17 | // clé primaire double | ||
| 18 | // inconvénient: impossible d'utiliser deux fois la même paire node_data/asset, même pour des rôles différents | ||
| 19 | #[ORM\Id] | ||
| 20 | #[ORM\ManyToOne(targetEntity: NodeData::class, inversedBy: 'nda_collection')] | ||
| 21 | #[ORM\JoinColumn(name: 'node_data_id', referencedColumnName: 'id_node_data', onDelete: 'CASCADE')] | ||
| 22 | private NodeData $node_data; | ||
| 23 | |||
| 24 | #[ORM\Id] | ||
| 25 | #[ORM\ManyToOne(targetEntity: Asset::class)] | ||
| 26 | #[ORM\JoinColumn(name: 'asset_id', referencedColumnName: 'id_asset', onDelete: 'CASCADE')] | ||
| 27 | private Asset $asset; | ||
| 28 | |||
| 29 | #[ORM\Column(type: 'string', length: 50)] | ||
| 30 | private string $role; | ||
| 31 | |||
| 32 | public function __construct(NodeData $node_data, Asset $asset, string $role){ | ||
| 33 | $this->node_data = $node_data; | ||
| 34 | $this->asset = $asset; | ||
| 35 | $this->role = $role; | ||
| 36 | } | ||
| 37 | |||
| 38 | /*public function getNodeData(): NodeData | ||
| 39 | { | ||
| 40 | return $this->node_data; | ||
| 41 | }*/ | ||
| 42 | public function getAsset(): Asset | ||
| 43 | { | ||
| 44 | return $this->asset; | ||
| 45 | } | ||
| 46 | public function setAsset(Asset $asset): self | ||
| 47 | { | ||
| 48 | $this->asset = $asset; | ||
| 49 | return $this; | ||
| 50 | } | ||
| 51 | public function getRole(): string | ||
| 52 | { | ||
| 53 | return $this->role; | ||
| 54 | } | ||
| 55 | } | ||
diff --git a/src/view/FooterBuilder.php b/src/view/FooterBuilder.php index 35df010..fcb78e0 100644 --- a/src/view/FooterBuilder.php +++ b/src/view/FooterBuilder.php | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | declare(strict_types=1); | 4 | declare(strict_types=1); |
| 5 | 5 | ||
| 6 | use App\Entity\Node; | 6 | use App\Entity\Node; |
| 7 | use App\Entity\Asset; | ||
| 7 | 8 | ||
| 8 | class FooterBuilder extends AbstractBuilder | 9 | class FooterBuilder extends AbstractBuilder |
| 9 | { | 10 | { |
| @@ -13,12 +14,15 @@ class FooterBuilder extends AbstractBuilder | |||
| 13 | 14 | ||
| 14 | if(file_exists($viewFile)) | 15 | if(file_exists($viewFile)) |
| 15 | { | 16 | { |
| 16 | // $adresses postale et e-mail | 17 | $node_data = $node->getNodeData(); |
| 17 | if(!empty($node->getNodeData()->getData())) | 18 | // nom du contact, adresse et e-mail |
| 19 | if(!empty($node_data->getData())) | ||
| 18 | { | 20 | { |
| 19 | extract($node->getNodeData()->getData()); | 21 | extract($node_data->getData()); |
| 20 | } | 22 | } |
| 21 | 23 | ||
| 24 | $footer_logo = Asset::USER_PATH . $node_data->getAssetByRole('footer_logo')?->getFileName() ?? ''; | ||
| 25 | |||
| 22 | $this->useChildrenBuilder($node); | 26 | $this->useChildrenBuilder($node); |
| 23 | $breadcrumb = $this->html; | 27 | $breadcrumb = $this->html; |
| 24 | 28 | ||
diff --git a/src/view/HeadBuilder.php b/src/view/HeadBuilder.php index b3d78aa..fd7f751 100644 --- a/src/view/HeadBuilder.php +++ b/src/view/HeadBuilder.php | |||
| @@ -49,18 +49,9 @@ class HeadBuilder extends AbstractBuilder | |||
| 49 | $description = Model::$page_path->getLast()->getDescription(); | 49 | $description = Model::$page_path->getLast()->getDescription(); |
| 50 | 50 | ||
| 51 | // favicon | 51 | // favicon |
| 52 | /*foreach($node->getNodeData()->getImages() as $image) | 52 | // ?-> est l'opérateur de navigation sécurisée => LOVE! |
| 53 | { | 53 | $favicon = Asset::USER_PATH . ($favicon_object = $node->getNodeData()->getAssetByRole('head_favicon'))?->getFileName() ?? ''; |
| 54 | if(str_contains($image->getFileName(), 'favicon')) | 54 | $favicon_type = $favicon_object?->getMimeType() ?? ''; |
| 55 | { | ||
| 56 | $favicon = rtrim($image->getFilePathMini(), '/'); | ||
| 57 | $alt = $image->getAlt(); | ||
| 58 | } | ||
| 59 | }*/ | ||
| 60 | |||
| 61 | // en dur temporairement | ||
| 62 | $favicon = Asset::USER_PATH . 'favicon48x48.png'; | ||
| 63 | $alt = 'favicon'; | ||
| 64 | 55 | ||
| 65 | ob_start(); | 56 | ob_start(); |
| 66 | require $viewFile; | 57 | require $viewFile; |
diff --git a/src/view/HeaderBuilder.php b/src/view/HeaderBuilder.php index 3b45a11..44e244d 100644 --- a/src/view/HeaderBuilder.php +++ b/src/view/HeaderBuilder.php | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | declare(strict_types=1); | 4 | declare(strict_types=1); |
| 5 | 5 | ||
| 6 | use App\Entity\Asset; | ||
| 7 | use App\Entity\Node; | 6 | use App\Entity\Node; |
| 7 | use App\Entity\Asset; | ||
| 8 | 8 | ||
| 9 | class HeaderBuilder extends AbstractBuilder | 9 | class HeaderBuilder extends AbstractBuilder |
| 10 | { | 10 | { |
| @@ -35,18 +35,18 @@ class HeaderBuilder extends AbstractBuilder | |||
| 35 | 35 | ||
| 36 | if(file_exists($viewFile)) | 36 | if(file_exists($viewFile)) |
| 37 | { | 37 | { |
| 38 | $node_data = $node->getNodeData(); | ||
| 38 | // titre et description | 39 | // titre et description |
| 39 | // => retourne $titre, $description et le tableau associatif: $social | 40 | if(!empty($node_data->getData())) |
| 40 | if(!empty($node->getNodeData()->getData())) | ||
| 41 | { | 41 | { |
| 42 | extract($node->getNodeData()->getData()); | 42 | extract($node_data->getData()); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | // réseaux sociaux + logo dans l'entête | 45 | // réseaux sociaux + logo dans l'entête |
| 46 | $header_logo = Asset::USER_PATH . $node_data->getAssetByRole('header_logo')?->getFileName() ?? ''; | ||
| 47 | $header_background = Asset::USER_PATH . $node_data->getAssetByRole('header_background')?->getFileName() ?? ''; | ||
| 46 | $keys = array_keys($social); | 48 | $keys = array_keys($social); |
| 47 | $social_networks = ''; | 49 | $social_networks = ''; |
| 48 | //$header_logo; | ||
| 49 | //$header_background; | ||
| 50 | 50 | ||
| 51 | // nécéssite des entrées dans la table node_asset | 51 | // nécéssite des entrées dans la table node_asset |
| 52 | /*foreach($node->getNodeData()->getAssets() as $asset) | 52 | /*foreach($node->getNodeData()->getAssets() as $asset) |
| @@ -80,20 +80,21 @@ class HeaderBuilder extends AbstractBuilder | |||
| 80 | 80 | ||
| 81 | // boutons mode admin | 81 | // boutons mode admin |
| 82 | if($_SESSION['admin']){ | 82 | if($_SESSION['admin']){ |
| 83 | // assets dans classe editing_zone | ||
| 83 | $editing_zone_margin = '5px'; | 84 | $editing_zone_margin = '5px'; |
| 84 | $favicon = Asset::USER_PATH . 'favicon48x48.png'; // double le code dans HeadBuilder | 85 | $buttons_favicon = '<button id="head_favicon_open" onclick="head_favicon.open()"><img id="head_favicon_img" class="action_icon"> Favicon</button> |
| 85 | $buttons_favicon = '<button id="head_favicon_open" onclick="head_favicon.open()"><img id="head_favicon_img" class="action_icon" src="' . $favicon . '"> Favicon</button> | 86 | <script>document.getElementById(\'head_favicon_img\').src = window.Config.favicon;</script> |
| 86 | <img id="head_favicon_submit" class="action_icon hidden" src="assets/save.svg" onclick="head_favicon.submit()"> | 87 | <img id="head_favicon_submit" class="action_icon hidden" src="assets/save.svg" onclick="head_favicon.submit()"> |
| 87 | <img id="head_favicon_cancel" class="action_icon hidden" src="assets/close.svg" onclick="head_favicon.cancel()">'; | 88 | <img id="head_favicon_cancel" class="action_icon hidden" src="assets/close.svg" onclick="head_favicon.cancel()">'; |
| 88 | $background = Asset::USER_PATH . 'fond-piscine.jpg'; | 89 | $buttons_background = '<button id="header_background_open" onclick="header_background.open()"><img id="header_background_img" class="background_button" src="' . $header_background . '"> Image de fond</button> |
| 89 | $buttons_background = '<button id="header_background_open" onclick="header_background.open()"><img id="header_background_img" class="background_button" src="' . $background . '"> Image de fond</button> | ||
| 90 | <img id="header_background_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_background.submit()"> | 90 | <img id="header_background_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_background.submit()"> |
| 91 | <img id="header_background_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_background.cancel()">'; | 91 | <img id="header_background_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_background.cancel()">'; |
| 92 | 92 | ||
| 93 | // asset dans classe header_content | ||
| 93 | $buttons_header_logo = '<img id="header_logo_open" class="action_icon" src="assets/edit.svg" onclick="header_logo.open()"> | 94 | $buttons_header_logo = '<img id="header_logo_open" class="action_icon" src="assets/edit.svg" onclick="header_logo.open()"> |
| 94 | <img id="header_logo_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_logo.submit()"> | 95 | <img id="header_logo_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_logo.submit()"> |
| 95 | <img id="header_logo_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_logo.cancel()">'; | 96 | <img id="header_logo_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_logo.cancel()">'; |
| 96 | 97 | // texte dans classe header_content | |
| 97 | $buttons_header_title = '<img id="header_title_open" class="action_icon" src="assets/edit.svg" onclick="header_title.open()"> | 98 | $buttons_header_title = '<img id="header_title_open" class="action_icon" src="assets/edit.svg" onclick="header_title.open()"> |
| 98 | <img id="header_title_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_title.submit()"> | 99 | <img id="header_title_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_title.submit()"> |
| 99 | <img id="header_title_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_title.cancel()">'; | 100 | <img id="header_title_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_title.cancel()">'; |
diff --git a/src/view/templates/footer.php b/src/view/templates/footer.php index 2bb5a9e..4db38ae 100644 --- a/src/view/templates/footer.php +++ b/src/view/templates/footer.php | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | </div> | 20 | </div> |
| 21 | </div> | 21 | </div> |
| 22 | <div id="footer_logo"> | 22 | <div id="footer_logo"> |
| 23 | <a href="<?= new URL ?>"><img id="footer_logo_img" src="<?= $footer_logo ?>" alt="logo_alt"></a> | 23 | <a href="<?= new URL ?>"><img id="footer_logo_img" src="<?= $footer_logo ?? '' ?>" alt="logo_alt"></a> |
| 24 | <input type="file" id="footer_logo_input" class="hidden" accept="image/png, image/jpeg, image/gif, image/webp, image/tiff"> | 24 | <input type="file" id="footer_logo_input" class="hidden" accept="image/png, image/jpeg, image/gif, image/webp, image/tiff"> |
| 25 | <?= $buttons_footer_logo ?> | 25 | <?= $buttons_footer_logo ?> |
| 26 | </div> | 26 | </div> |
diff --git a/src/view/templates/head.php b/src/view/templates/head.php index 83a0e7c..bce0a19 100644 --- a/src/view/templates/head.php +++ b/src/view/templates/head.php | |||
| @@ -2,12 +2,12 @@ | |||
| 2 | <!DOCTYPE html> | 2 | <!DOCTYPE html> |
| 3 | <html lang="fr"> | 3 | <html lang="fr"> |
| 4 | <head> | 4 | <head> |
| 5 | <script>window.Config = {page: "<?= CURRENT_PAGE ?>", favicon: "<?= $favicon ?>"};</script> | ||
| 5 | <meta charset="utf-8"> | 6 | <meta charset="utf-8"> |
| 6 | <title><?= $title ?></title> | 7 | <title><?= $title ?></title> |
| 7 | <link rel="icon" type="image/png" href="<?= $favicon ?>" alt="<?= $alt ?>"> | 8 | <link rel="icon" type="<?= $favicon_type ?>" href="<?= $favicon ?>"> |
| 8 | <meta name="description" content="<?= $description ?>"> | 9 | <meta name="description" content="<?= $description ?>"> |
| 9 | <meta name="viewport" content="width=device-width"> | 10 | <meta name="viewport" content="width=device-width"> |
| 10 | <script>window.Config = {page: "<?= CURRENT_PAGE ?>"};</script> | ||
| 11 | <?= $css ?> | 11 | <?= $css ?> |
| 12 | <?= $js ?> | 12 | <?= $js ?> |
| 13 | </head> \ No newline at end of file | 13 | </head> \ No newline at end of file |
diff --git a/src/view/templates/header.php b/src/view/templates/header.php index b63aa84..ac8af7f 100644 --- a/src/view/templates/header.php +++ b/src/view/templates/header.php | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | <div class="header_content"> | 18 | <div class="header_content"> |
| 19 | <div class="header_left_col"> | 19 | <div class="header_left_col"> |
| 20 | <div id="header_logo"> | 20 | <div id="header_logo"> |
| 21 | <a href="<?= new URL ?>"><img id="header_logo_img" src="<?= $header_logo ?>" alt="logo_alt"></a> | 21 | <a href="<?= new URL ?>"><img id="header_logo_img" src="<?= $header_logo ?? '' ?>" alt="header_logo"></a> |
| 22 | <input type="file" id="header_logo_input" class="hidden" accept="image/png, image/jpeg, image/gif, image/webp, image/tiff"> | 22 | <input type="file" id="header_logo_input" class="hidden" accept="image/png, image/jpeg, image/gif, image/webp, image/tiff"> |
| 23 | <?= $buttons_header_logo ?> | 23 | <?= $buttons_header_logo ?> |
| 24 | </div> | 24 | </div> |
