Ergänzt AJAX-Livesuche für Seiten, Beiträge und Mediathek
This commit is contained in:
1 parent
11b60fc5d8
commit
41d87f62a4
20 files changed
+703
-311
No files matched your search
@@ -39,17 +39,22 @@ final class MediaLibrary
|
||||
*
|
||||
* @return array{items: list<array<string, mixed>>, total: int, page: int, pages: int, perPage: int}
|
||||
*/
|
||||
public function page(int $page, bool $withArchived = false, int $perPage = self::PER_PAGE): array
|
||||
public function page(int $page, bool $withArchived = false, int $perPage = self::PER_PAGE, string $query = ''): array
|
||||
{
|
||||
$where = $withArchived ? '' : ' WHERE archived = 0';
|
||||
$total = (int) $this->db->fetchOne('SELECT COUNT(*) FROM media'.$where);
|
||||
$qb = $this->db->createQueryBuilder()->from('media');
|
||||
if (!$withArchived) {
|
||||
$qb->andWhere('archived = 0');
|
||||
}
|
||||
if ('' !== trim($query)) {
|
||||
$qb->andWhere('(LOWER(title) LIKE :query ESCAPE \'!\' OR LOWER(alt) LIKE :query ESCAPE \'!\')')
|
||||
->setParameter('query', '%'.str_replace(['!', '%', '_'], ['!!', '!%', '!_'], mb_strtolower(trim($query))).'%');
|
||||
}
|
||||
$total = (int) (clone $qb)->select('COUNT(*)')->executeQuery()->fetchOne();
|
||||
$perPage = max(1, min(96, $perPage));
|
||||
$pages = max(1, (int) ceil($total / $perPage));
|
||||
$page = max(1, min($pages, $page));
|
||||
$items = $this->db->fetchAllAssociative(
|
||||
'SELECT * FROM media'.$where.' ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?',
|
||||
[$perPage, ($page - 1) * $perPage],
|
||||
);
|
||||
$items = $qb->select('*')->orderBy('created_at', 'DESC')->addOrderBy('id', 'DESC')
|
||||
->setMaxResults($perPage)->setFirstResult(($page - 1) * $perPage)->executeQuery()->fetchAllAssociative();
|
||||
|
||||
return [
|
||||
'items' => array_map($this->present(...), $items),
|
||||
|
||||
@@ -54,14 +54,23 @@ final class EditorController extends AbstractController
|
||||
}
|
||||
unset($page);
|
||||
|
||||
return $this->render('admin/pages.html.twig', [
|
||||
$view = [
|
||||
'pages' => 'trash' === $status ? [] : $pages,
|
||||
'trash' => 'trash' === $status ? array_map(static fn (array $p): array => [...$p, 'deletedAt' => $p['deleted_at']], $pages) : [],
|
||||
'parentChoices' => $parentChoices, 'postLayouts' => PostLayouts::all(),
|
||||
'contentType' => $type, 'result' => $result, 'query' => $query, 'status' => $status,
|
||||
'listRoute' => 'post' === $type ? 'admin_posts' : 'admin_pages',
|
||||
'areaChoices' => ['header' => $this->partials->choices('header'), 'footer' => $this->partials->choices('footer')],
|
||||
]);
|
||||
];
|
||||
if ($request->isXmlHttpRequest()) {
|
||||
return $this->json([
|
||||
'html' => $this->renderView('admin/content-results.html.twig', $view),
|
||||
'total' => $result['total'],
|
||||
'parameters' => ['q' => $query, 'status' => $status, 'limit' => $result['limit'], 'seite' => $result['page']],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render('admin/pages.html.twig', $view);
|
||||
}
|
||||
|
||||
#[Route('/api/content-choices', name: 'admin_content_choices', methods: ['GET'])]
|
||||
|
||||
@@ -24,11 +24,18 @@ final class MediaController extends AbstractController
|
||||
// The screen renders the images itself, page by page. The dialog stays what it is: the way
|
||||
// to pick an image while editing, not the way to see what the library holds.
|
||||
$archived = $request->query->getBoolean('archiv');
|
||||
$query = mb_substr(trim($request->query->getString('q')), 0, 160);
|
||||
$library = $this->media->page($request->query->getInt('seite', 1), $archived, query: $query);
|
||||
$view = ['library' => $library, 'archived' => $archived, 'query' => $query];
|
||||
if ($request->isXmlHttpRequest()) {
|
||||
return $this->json([
|
||||
'html' => $this->renderView('admin/media-results.html.twig', $view),
|
||||
'total' => $library['total'],
|
||||
'parameters' => ['q' => $query, 'archiv' => $archived ? '1' : '0', 'seite' => $library['page']],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render('admin/media.html.twig', [
|
||||
'library' => $this->media->page($request->query->getInt('seite', 1), $archived),
|
||||
'archived' => $archived,
|
||||
]);
|
||||
return $this->render('admin/media.html.twig', $view);
|
||||
}
|
||||
|
||||
#[Route('/%kant.admin_path%/media/upload', name: 'admin_media_upload', methods: ['POST'])]
|
||||
@@ -90,7 +97,8 @@ final class MediaController extends AbstractController
|
||||
$query = array_filter([
|
||||
'seite' => $request->request->getInt('seite', 1) > 1 ? $request->request->getInt('seite') : null,
|
||||
'archiv' => $request->request->getBoolean('archiv') ? '1' : null,
|
||||
]);
|
||||
'q' => mb_substr(trim($request->request->getString('q')), 0, 160),
|
||||
], static fn ($value): bool => null !== $value && '' !== $value);
|
||||
|
||||
return $this->redirectToRoute('admin_media', $query);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ final class ConnectionFactory
|
||||
}
|
||||
$connection = DriverManager::getConnection($params, $configuration);
|
||||
if ('pdo_sqlite' === $params['driver']) {
|
||||
// SQLite's built-in LOWER only handles ASCII: searching for "über" must also find
|
||||
// "Über uns", just as on MySQL. No database rewrite or search-specific schema needed.
|
||||
$connection->getNativeConnection()->sqliteCreateFunction('lower', static fn (?string $value): ?string => null === $value ? null : mb_strtolower($value, 'UTF-8'), 1, \PDO::SQLITE_DETERMINISTIC);
|
||||
$connection->executeStatement('PRAGMA foreign_keys = ON');
|
||||
$connection->executeStatement('PRAGMA busy_timeout = 5000');
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user