Rapports SQL personnalisés
Alimentez une grille avec une instruction SELECT arbitraire en lecture seule via query(), pour les rapports qui ne correspondent pas à une seule table.
table() contre query()
->table($name) alimente une grille avec une seule table réelle et modifiable. ->query($sql) est l'alternative pour tout ce qui ne correspond pas à une seule table - jointures, agrégats, colonnes calculées couvrant plusieurs tables :
public function query(string $sql): self
$sql est utilisé tel quel, enveloppé comme une table dérivée par la couche API - exactement le même niveau de confiance que les échappatoires SQL brut de where_raw()/subselect(). Il doit s'agir d'une chaîne simple que vous avez écrite vous-même dans le PHP de votre page, jamais quelque chose construit à partir d'une entrée de requête.
Le mode rapport est en lecture seule
Une grille en mode query n'a ni Ajouter/Modifier/Supprimer, ni actions groupées, ni édition en ligne - elle est en lecture seule par nature, puisqu'il n'y a pas de table unique qu'une écriture pourrait cibler sans ambiguïté. Ceci est appliqué à la fois côté client et côté serveur : l'API rejette purement et simplement les requêtes POST/PUT/DELETE contre une route en mode query, quoi qu'envoie le client. Seuls lister/rechercher/trier/paginer/exporter restent disponibles.
columns() et route() restent requis
Une grille en mode query n'ouvre jamais sa propre connexion à la base de données pour découvrir les colonnes - sa liste de colonnes est uniquement celle indiquée par ->columns(). ->route() est également requis puisqu'il n'y a pas de nom de table dont en déduire un par défaut.
Un exemple basé sur une JOIN
$xcrud = Xcrud::get_instance();
$xcrud->route('order-summary');
$xcrud->query(
'SELECT o.orderNumber, o.orderDate, o.status, c.customerName, c.country,
COUNT(od.id) AS itemCount,
SUM(od.quantityOrdered * od.priceEach) AS orderTotal
FROM orders o
JOIN customers c ON c.customerNumber = o.customerNumber
JOIN orderdetails od ON od.orderNumber = o.orderNumber
GROUP BY o.orderNumber, o.orderDate, o.status, c.customerName, c.country'
);
$xcrud->columns('orderNumber,orderDate,status,customerName,country,itemCount,orderTotal');
$xcrud->order_by('orderTotal', 'desc');
$xcrud->title('Order Summary Report');
echo $xcrud->render();
Les alias de colonnes propres à $sql et les noms de ->columns() ne sont jamais recoupés entre eux (aucun accès à la base de données n'a lieu au moment du rendu) - une incohérence apparaît sous forme d'erreur lors de la première vraie requête de la grille, et non comme une exception au moment du rendu, contrairement à ce que produirait un nom de colonne inconnu dans order_by()/label()/where(). Vérifiez les deux listes manuellement.
Un ORDER BY final à l'intérieur de $sql sans LIMIT peut être silencieusement abandonné une fois enveloppé comme table dérivée - sans conséquence, puisque le propre tri de la grille/->order_by() applique toujours un ORDER BY externe quoi qu'il arrive, mais ne comptez pas sur un ORDER BY interne pour produire un quelconque effet à lui seul.