Simplification
This commit is contained in:
@@ -29,9 +29,10 @@ class Media extends DB\SQL\Mapper
|
||||
public function page(int $page, int $perPage): array
|
||||
{
|
||||
$result = $this->paginate(max(0, $page - 1), $perPage, null, ['order' => 'created_at DESC, id DESC']);
|
||||
$items = array_map(fn(self $row): array => $this->decorate($row->cast()), $result['subset'] ?: []);
|
||||
|
||||
return [
|
||||
'items' => array_map(fn(self $row): array => $this->decorate($row->cast()), $result['subset'] ?: []),
|
||||
'items' => $items,
|
||||
'pagination' => [
|
||||
'page' => max(1, min($page, $result['count'] ?: 1)),
|
||||
'pages' => max(1, (int) ($result['count'] ?: 1)),
|
||||
@@ -39,14 +40,6 @@ class Media extends DB\SQL\Mapper
|
||||
];
|
||||
}
|
||||
|
||||
public function recent(int $limit): array
|
||||
{
|
||||
return array_map(
|
||||
fn(self $row): array => $this->decorate($row->cast()),
|
||||
$this->find(null, ['order' => 'created_at DESC, id DESC', 'limit' => $limit]) ?: []
|
||||
);
|
||||
}
|
||||
|
||||
public function findById(int $id): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
@@ -63,18 +56,22 @@ class Media extends DB\SQL\Mapper
|
||||
return $this->dry() ? null : $this->decorate($this->cast());
|
||||
}
|
||||
|
||||
public function upload(string $path, string $originalName = ''): int
|
||||
public function upload(string $temporaryPath, string $originalName = ''): int
|
||||
{
|
||||
if (!is_file($path)) {
|
||||
$f3 = Base::instance();
|
||||
|
||||
if (!is_file($temporaryPath)) {
|
||||
throw new RuntimeException('Fichier image introuvable.');
|
||||
}
|
||||
|
||||
$info = @getimagesize($path);
|
||||
if (!is_array($info)) {
|
||||
@unlink($path);
|
||||
$binary = $f3->read($temporaryPath);
|
||||
$image = new Image();
|
||||
if ($binary === '' || $image->load($binary) === false) {
|
||||
@unlink($temporaryPath);
|
||||
throw new RuntimeException('Fichier image invalide.');
|
||||
}
|
||||
|
||||
$info = @getimagesizefromstring($binary);
|
||||
$mime = strtolower((string) ($info['mime'] ?? ''));
|
||||
$extension = match ($mime) {
|
||||
'image/jpeg' => 'jpg',
|
||||
@@ -83,28 +80,39 @@ class Media extends DB\SQL\Mapper
|
||||
};
|
||||
|
||||
if ($extension === null) {
|
||||
@unlink($path);
|
||||
@unlink($temporaryPath);
|
||||
throw new RuntimeException('Format non supporté. Utilise JPG ou PNG.');
|
||||
}
|
||||
|
||||
$fileName = bin2hex(random_bytes(16)) . '.' . $extension;
|
||||
$target = rtrim((string) Base::instance()->get('paths.media_dir'), '/\\') . DIRECTORY_SEPARATOR . $fileName;
|
||||
$encoded = match ($extension) {
|
||||
'jpg' => $image->dump('jpeg', 90),
|
||||
'png' => $image->dump('png'),
|
||||
};
|
||||
|
||||
if (!@rename($path, $target)) {
|
||||
if (!@copy($path, $target)) {
|
||||
@unlink($path);
|
||||
throw new RuntimeException('Impossible d’enregistrer cette image.');
|
||||
}
|
||||
@unlink($path);
|
||||
$fileName = bin2hex(random_bytes(16)) . '.' . $extension;
|
||||
$target = $this->storagePath($fileName);
|
||||
|
||||
try {
|
||||
$f3->write($target, $encoded);
|
||||
} catch (Throwable $e) {
|
||||
@unlink($temporaryPath);
|
||||
throw new RuntimeException('Impossible d’enregistrer cette image.', 0, $e);
|
||||
}
|
||||
|
||||
$this->reset();
|
||||
$this->file_name = $fileName;
|
||||
$this->alt = $this->altFromName($originalName);
|
||||
$this->width = (int) $info[0];
|
||||
$this->height = (int) $info[1];
|
||||
$this->created_at = app_now();
|
||||
$this->save();
|
||||
@unlink($temporaryPath);
|
||||
|
||||
try {
|
||||
$this->reset();
|
||||
$this->file_name = $fileName;
|
||||
$this->alt = $this->guessAlt($originalName);
|
||||
$this->width = $image->width();
|
||||
$this->height = $image->height();
|
||||
$this->created_at = app_now();
|
||||
$this->save();
|
||||
} catch (Throwable $e) {
|
||||
@unlink($target);
|
||||
throw new RuntimeException('Impossible de finaliser cette image.', 0, $e);
|
||||
}
|
||||
|
||||
return (int) $this->id;
|
||||
}
|
||||
@@ -127,34 +135,41 @@ class Media extends DB\SQL\Mapper
|
||||
throw new RuntimeException('Image introuvable.');
|
||||
}
|
||||
|
||||
$path = rtrim((string) Base::instance()->get('paths.media_dir'), '/\\') . DIRECTORY_SEPARATOR . $this->file_name;
|
||||
$this->erase();
|
||||
if (is_file($path)) {
|
||||
@unlink($path);
|
||||
try {
|
||||
$this->erase();
|
||||
} catch (Throwable $e) {
|
||||
throw new RuntimeException('Impossible de supprimer cette image.', 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function decorate(array $row): array
|
||||
{
|
||||
$file = (string) $row['file_name'];
|
||||
$fileName = (string) $row['file_name'];
|
||||
$alt = (string) $row['alt'];
|
||||
$base = rtrim((string) Base::instance()->get('BASE'), '/');
|
||||
$mediaBase = rtrim((string) Base::instance()->get('paths.media_base'), '/');
|
||||
|
||||
return [
|
||||
'id' => (int) $row['id'],
|
||||
'file_name' => $file,
|
||||
'file_name' => $fileName,
|
||||
'alt' => $alt,
|
||||
'width' => (int) $row['width'],
|
||||
'height' => (int) $row['height'],
|
||||
'created_at' => (string) $row['created_at'],
|
||||
'url' => rtrim((string) Base::instance()->get('BASE'), '/') . rtrim((string) Base::instance()->get('paths.media_base'), '/') . '/' . rawurlencode($file),
|
||||
'markdown' => '',
|
||||
'url' => $base . $mediaBase . '/' . rawurlencode($fileName),
|
||||
'markdown' => '',
|
||||
];
|
||||
}
|
||||
|
||||
private function altFromName(string $name): string
|
||||
private function storagePath(string $fileName): string
|
||||
{
|
||||
$name = trim(pathinfo($name, PATHINFO_FILENAME));
|
||||
$name = preg_replace('/[-_]+/', ' ', $name) ?: '';
|
||||
return trim($name);
|
||||
return rtrim((string) Base::instance()->get('paths.media_dir'), '/\\') . DIRECTORY_SEPARATOR . $fileName;
|
||||
}
|
||||
|
||||
private function guessAlt(string $originalName): string
|
||||
{
|
||||
$label = trim(pathinfo($originalName, PATHINFO_FILENAME));
|
||||
$label = preg_replace('/[-_]+/', ' ', $label) ?: '';
|
||||
return trim($label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,13 +62,16 @@ class Post extends DB\SQL\Mapper
|
||||
}
|
||||
|
||||
$row = $this->cast();
|
||||
$post = $this->summary($row) + ['body_html' => (string) $row['body_html']];
|
||||
|
||||
return $post;
|
||||
return $this->summary($row) + ['body_html' => (string) $row['body_html']];
|
||||
}
|
||||
|
||||
public function findForForm(int $id): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->load(['id = ?', $id]);
|
||||
if ($this->dry()) {
|
||||
return null;
|
||||
@@ -84,12 +87,12 @@ class Post extends DB\SQL\Mapper
|
||||
|
||||
public function savePost(array $input, ?int $id = null): int
|
||||
{
|
||||
$payload = $this->payload($input);
|
||||
$payload = $this->normalizePayload($input);
|
||||
$now = app_now();
|
||||
|
||||
if ($id === null) {
|
||||
$this->reset();
|
||||
$payload['slug'] = $this->uniqueSlug($payload['title']);
|
||||
$payload['slug'] = $this->nextSlug($payload['title']);
|
||||
$payload['created_at'] = $now;
|
||||
} else {
|
||||
$this->load(['id = ?', $id]);
|
||||
@@ -120,11 +123,11 @@ class Post extends DB\SQL\Mapper
|
||||
return $this->count(['body_markdown LIKE ?', '%media:' . $fileName . '%']) > 0;
|
||||
}
|
||||
|
||||
private function payload(array $input): array
|
||||
private function normalizePayload(array $input): array
|
||||
{
|
||||
$title = trim((string) ($input['title'] ?? ''));
|
||||
$excerpt = trim((string) ($input['excerpt'] ?? ''));
|
||||
$body = trim((string) ($input['body_markdown'] ?? ''));
|
||||
$bodyMarkdown = trim((string) ($input['body_markdown'] ?? ''));
|
||||
|
||||
if ($title === '') {
|
||||
throw new RuntimeException('Ajoute un titre.');
|
||||
@@ -142,20 +145,20 @@ class Post extends DB\SQL\Mapper
|
||||
return [
|
||||
'title' => $title,
|
||||
'excerpt' => $excerpt,
|
||||
'body_markdown' => $body,
|
||||
'body_html' => MarkdownService::instance()->compile($body, new Media()),
|
||||
'body_markdown' => $bodyMarkdown,
|
||||
'body_html' => MarkdownService::instance()->compile($bodyMarkdown, new Media()),
|
||||
];
|
||||
}
|
||||
|
||||
private function uniqueSlug(string $title): string
|
||||
private function nextSlug(string $title): string
|
||||
{
|
||||
$base = app_slug($title);
|
||||
$slug = $base;
|
||||
$n = 2;
|
||||
$suffix = 2;
|
||||
|
||||
while ($this->count(['slug = ?', $slug]) > 0) {
|
||||
$slug = $base . '-' . $n;
|
||||
$n++;
|
||||
$slug = $base . '-' . $suffix;
|
||||
$suffix++;
|
||||
}
|
||||
|
||||
return $slug;
|
||||
@@ -163,7 +166,7 @@ class Post extends DB\SQL\Mapper
|
||||
|
||||
private function summary(array $row): array
|
||||
{
|
||||
$thumbnail = $this->firstImage((string) ($row['body_html'] ?? ''));
|
||||
$thumbnail = $this->extractThumbnail((string) ($row['body_html'] ?? ''));
|
||||
|
||||
return [
|
||||
'id' => (int) $row['id'],
|
||||
@@ -177,20 +180,14 @@ class Post extends DB\SQL\Mapper
|
||||
];
|
||||
}
|
||||
|
||||
private function firstImage(string $html): array
|
||||
private function extractThumbnail(string $html): array
|
||||
{
|
||||
if ($html === '') {
|
||||
if ($html === '' || !preg_match('~(<img\s[^>]*src="([^"]+)"[^>]*>)~i', $html, $match)) {
|
||||
return ['url' => '', 'alt' => ''];
|
||||
}
|
||||
|
||||
if (!preg_match('~(<img\s[^>]*src="([^"]+)"[^>]*>)~i', $html, $match)) {
|
||||
return ['url' => '', 'alt' => ''];
|
||||
}
|
||||
|
||||
$tag = $match[1];
|
||||
$alt = '';
|
||||
|
||||
if (preg_match('~alt="([^"]*)"~i', $tag, $altMatch)) {
|
||||
if (preg_match('~alt="([^"]*)"~i', $match[1], $altMatch)) {
|
||||
$alt = html_entity_decode($altMatch[1], ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ class User extends DB\SQL\Mapper
|
||||
|
||||
public function findPublic(int $id): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->load(['id = ?', $id]);
|
||||
if ($this->dry()) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user