Added Models
This commit is contained in:
@@ -9,6 +9,7 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\Views\Twig;
|
||||
use App\Repositories\PostRepositoryInterface as PostRepository;
|
||||
use App\Requests\PostRequest;
|
||||
use App\Models\Post;
|
||||
|
||||
/**
|
||||
* Contrôleur pour les posts.
|
||||
@@ -26,7 +27,7 @@ class PostController
|
||||
|
||||
public function index(Request $req, Response $res): Response
|
||||
{
|
||||
$posts = $this->repo->allDesc();
|
||||
$posts = $this->repo->allDesc(); // Post[]
|
||||
return $this->view->render($res, 'pages/home.twig', ['posts' => $posts]);
|
||||
}
|
||||
|
||||
@@ -51,9 +52,11 @@ class PostController
|
||||
|
||||
// Si id fourni mais post introuvable -> 404
|
||||
if ($id > 0 && $post === null) {
|
||||
return $res->withStatus(404)->write('Article non trouvé');
|
||||
$res->getBody()->write('Article non trouvé');
|
||||
return $res->withStatus(404);
|
||||
}
|
||||
|
||||
// Twig peut accéder aux getters (post.title, post.content)
|
||||
$action = $id ? "/admin/edit/{$id}" : "/admin/create";
|
||||
return $this->view->render($res, 'pages/post_form.twig', ['post' => $post, 'action' => $action]);
|
||||
}
|
||||
@@ -62,12 +65,12 @@ class PostController
|
||||
{
|
||||
$postRequest = PostRequest::fromArray($req->getParsedBody());
|
||||
if (! $postRequest->isValid()) {
|
||||
// Simple gestion d'erreur : rediriger vers admin (on peut ajouter flash messages plus tard)
|
||||
return $res->withHeader('Location', '/admin')->withStatus(302);
|
||||
}
|
||||
|
||||
$data = $postRequest->validated();
|
||||
$this->repo->create($data);
|
||||
// Utilisation du helper toModel() pour construire l'entité Post
|
||||
$post = $postRequest->toModel(0);
|
||||
$this->repo->create($post);
|
||||
return $res->withHeader('Location', '/admin')->withStatus(302);
|
||||
}
|
||||
|
||||
@@ -76,7 +79,8 @@ class PostController
|
||||
$id = (int)$args['id'];
|
||||
$existing = $this->repo->find($id);
|
||||
if ($existing === null) {
|
||||
return $res->withStatus(404)->write('Article non trouvé');
|
||||
$res->getBody()->write('Article non trouvé');
|
||||
return $res->withStatus(404);
|
||||
}
|
||||
|
||||
$postRequest = PostRequest::fromArray($req->getParsedBody());
|
||||
@@ -84,8 +88,8 @@ class PostController
|
||||
return $res->withHeader('Location', '/admin')->withStatus(302);
|
||||
}
|
||||
|
||||
$data = $postRequest->validated();
|
||||
$this->repo->update($id, $data);
|
||||
$post = $postRequest->toModel($id);
|
||||
$this->repo->update($id, $post);
|
||||
return $res->withHeader('Location', '/admin')->withStatus(302);
|
||||
}
|
||||
|
||||
@@ -94,7 +98,8 @@ class PostController
|
||||
$id = (int)$args['id'];
|
||||
$existing = $this->repo->find($id);
|
||||
if ($existing === null) {
|
||||
return $res->withStatus(404)->write('Article non trouvé');
|
||||
$res->getBody()->write('Article non trouvé');
|
||||
return $res->withStatus(404);
|
||||
}
|
||||
|
||||
$this->repo->delete($id);
|
||||
|
||||
78
src/Models/Post.php
Normal file
78
src/Models/Post.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* Représente un post (DTO / entité légère).
|
||||
*
|
||||
* Cette classe est immuable par simplicité : on construit une instance
|
||||
* depuis les données (DB ou formulaire) et on récupère ses valeurs via des getters.
|
||||
*/
|
||||
final class Post
|
||||
{
|
||||
private int $id;
|
||||
private string $title;
|
||||
private string $content;
|
||||
|
||||
/**
|
||||
* @param int $id Identifiant (0 si non persisté)
|
||||
* @param string $title Titre de l'article
|
||||
* @param string $content Contenu HTML ou texte de l'article
|
||||
*/
|
||||
public function __construct(int $id, string $title, string $content)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->title = $title;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une instance depuis un tableau (par ex. ligne DB ou formulaire).
|
||||
*
|
||||
* Ce helper facilite la migration depuis le format tableau existant.
|
||||
*
|
||||
* @param array<string,mixed> $data Clé 'id' (optionnelle), 'title', 'content'
|
||||
* @return self
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$id = isset($data['id']) ? (int)$data['id'] : 0;
|
||||
$title = isset($data['title']) ? (string)$data['title'] : '';
|
||||
$content = isset($data['content']) ? (string)$data['content'] : '';
|
||||
|
||||
return new self($id, $title, $content);
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne un tableau simple utile pour la persistance.
|
||||
*
|
||||
* @return array{title:string,content:string}
|
||||
*/
|
||||
public function toPersistableArray(): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'content' => $this->content,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Post;
|
||||
|
||||
/**
|
||||
* Interface décrivant les opérations sur les posts.
|
||||
*/
|
||||
@@ -12,7 +14,7 @@ interface PostRepositoryInterface
|
||||
/**
|
||||
* Retourne tous les posts triés par id descendant.
|
||||
*
|
||||
* @return array<int, array{id:int, title:string, content:string}>
|
||||
* @return Post[] Tableau d'objets Post
|
||||
*/
|
||||
public function allDesc(): array;
|
||||
|
||||
@@ -20,26 +22,26 @@ interface PostRepositoryInterface
|
||||
* Trouve un post par son id.
|
||||
*
|
||||
* @param int $id
|
||||
* @return array{id:int, title:string, content:string}|null
|
||||
* @return Post|null
|
||||
*/
|
||||
public function find(int $id): ?array;
|
||||
public function find(int $id): ?Post;
|
||||
|
||||
/**
|
||||
* Crée un post.
|
||||
*
|
||||
* @param array{title:string,content:string} $data
|
||||
* @param Post $post Instance contenant les données à insérer (id ignoré)
|
||||
* @return int id inséré
|
||||
*/
|
||||
public function create(array $data): int;
|
||||
public function create(Post $post): int;
|
||||
|
||||
/**
|
||||
* Met à jour un post.
|
||||
*
|
||||
* @param int $id
|
||||
* @param array{title:string,content:string} $data
|
||||
* @param Post $post Données à mettre à jour (id ignoré)
|
||||
* @return void
|
||||
*/
|
||||
public function update(int $id, array $data): void;
|
||||
public function update(int $id, Post $post): void;
|
||||
|
||||
/**
|
||||
* Supprime un post.
|
||||
|
||||
@@ -5,10 +5,12 @@ declare(strict_types=1);
|
||||
namespace App\Repositories;
|
||||
|
||||
use Medoo\Medoo;
|
||||
use App\Models\Post;
|
||||
|
||||
/**
|
||||
* Repository pour "post" basé sur Medoo.
|
||||
* Retourne et consomme des tableaux associatifs.
|
||||
*
|
||||
* Cette implémentation convertit les lignes DB en objets App\Models\Post.
|
||||
*/
|
||||
class PostRepositoryMedoo implements PostRepositoryInterface
|
||||
{
|
||||
@@ -25,19 +27,23 @@ class PostRepositoryMedoo implements PostRepositoryInterface
|
||||
public function allDesc(): array
|
||||
{
|
||||
$rows = $this->db->select('post', ['id', 'title', 'content'], ['ORDER' => ['id' => 'DESC']]);
|
||||
return is_array($rows) ? array_map(function ($r) {
|
||||
return [
|
||||
'id' => (int)($r['id'] ?? 0),
|
||||
'title' => (string)($r['title'] ?? ''),
|
||||
'content' => (string)($r['content'] ?? ''),
|
||||
];
|
||||
}, $rows) : [];
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_map(function ($r) {
|
||||
return new Post(
|
||||
(int)($r['id'] ?? 0),
|
||||
(string)($r['title'] ?? ''),
|
||||
(string)($r['content'] ?? '')
|
||||
);
|
||||
}, $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function find(int $id): ?array
|
||||
public function find(int $id): ?Post
|
||||
{
|
||||
$row = $this->db->get('post', ['id', 'title', 'content'], ['id' => $id]);
|
||||
|
||||
@@ -45,34 +51,31 @@ class PostRepositoryMedoo implements PostRepositoryInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (int)($row['id'] ?? 0),
|
||||
'title' => (string)($row['title'] ?? ''),
|
||||
'content' => (string)($row['content'] ?? ''),
|
||||
];
|
||||
return new Post(
|
||||
(int)($row['id'] ?? 0),
|
||||
(string)($row['title'] ?? ''),
|
||||
(string)($row['content'] ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function create(array $data): int
|
||||
public function create(Post $post): int
|
||||
{
|
||||
$this->db->insert('post', [
|
||||
'title' => $data['title'] ?? '',
|
||||
'content' => $data['content'] ?? '',
|
||||
]);
|
||||
$data = $post->toPersistableArray();
|
||||
|
||||
$this->db->insert('post', $data);
|
||||
return (int)$this->db->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function update(int $id, array $data): void
|
||||
public function update(int $id, Post $post): void
|
||||
{
|
||||
$this->db->update('post', [
|
||||
'title' => $data['title'] ?? '',
|
||||
'content' => $data['content'] ?? '',
|
||||
], ['id' => $id]);
|
||||
$data = $post->toPersistableArray();
|
||||
$this->db->update('post', $data, ['id' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Requests;
|
||||
|
||||
use App\Models\Post;
|
||||
|
||||
/**
|
||||
* Classe simple responsable de la validation / sanitation des données
|
||||
* provenant des formulaires de post.
|
||||
@@ -65,4 +67,17 @@ final class PostRequest
|
||||
{
|
||||
return $this->title !== '' && $this->content !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit la requête validée en modèle App\Models\Post.
|
||||
*
|
||||
* Ce helper facilite la construction d'un Post directement depuis la requête.
|
||||
*
|
||||
* @param int $id Identifiant (0 si nouvel enregistrement)
|
||||
* @return Post
|
||||
*/
|
||||
public function toModel(int $id = 0): Post
|
||||
{
|
||||
return new Post($id, $this->title, $this->content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,4 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<p>Aucun article publié.</p>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<p>
|
||||
<label>Contenu<br>
|
||||
<textarea id="editor" name="content" rows="6" {# required <- removed because conflicts with TinyMCE#}>{{ post.content|default('') }}</textarea>
|
||||
<textarea id="editor" name="content" rows="6" >{{ post.content|default('') }}</textarea>
|
||||
</label>
|
||||
</p>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<script>
|
||||
tinymce.init({
|
||||
selector: '#editor',
|
||||
base_url: '/js/tinymce', // assure le bon chemin relatif
|
||||
base_url: '/js/tinymce',
|
||||
license_key: 'gpl',
|
||||
height: 400,
|
||||
menubar: false,
|
||||
|
||||
Reference in New Issue
Block a user