Produkty Objednávky Zákazníci Dokumentace
Nepřihlášen Uživatel 1 Uživatel 2 Uživatel 3
Část II · Zdroje dat

3.3. JOIN, pohledy a počítané sloupce

Dotaz může spojovat, počítat i vnořovat – pro grid je výsledek pořád jen sada pojmenovaných sloupců.

Ukázka

Jméno zákazníka z druhé tabulky, počet položek ze třetí. Filtrovat i řadit jde podle obojího.

Zdrojový kód

php app/Modules/AdminModule/Components/Docs/Data/SqlJoinGridControl/SqlJoinGridControl.php
<?php

declare(strict_types=1);

namespace App\Components\Docs\Data\SqlJoinGridControl;

use App\Enum\OrderStatus;
use Xart\Grid\Button\ButtonManager;
use Xart\Grid\Column\ColumnManager;
use Xart\Grid\Control\GridControl;
use Xart\Grid\DataOutput\Row;
use Xart\Grid\DataSource\DataSource;
use Xart\Grid\DataSource\SQL\SQLDataSource;

/**
 * Dokumentace, kapitola 3.3 – JOIN, pohledy a počítané sloupce.
 *
 * Objednávky se jménem zákazníka z druhé tabulky a s počtem položek z třetí. Filtrovat i řadit jde
 * podle obojího: grid si za alias dosadí výraz z dotazu, ne alias samotný.
 */
class SqlJoinGridControl extends GridControl
{
    public function createDataSource(): DataSource
    {
        return new SQLDataSource(__DIR__ . '/SqlJoinGridControl.sql');
    }


    public function columns(ColumnManager $cm): void
    {
        $cm->add('number', 'Číslo');

        // Sloupec z JOINované tabulky – filtr se poskládá nad výrazem CONCAT(...), ne nad aliasem.
        $cm->add('customer', 'Zákazník');
        $cm->addEmail('email', 'E-mail');

        $cm->addEnum('status', 'Stav', OrderStatus::class);
        $cm->addNumber('total_price', 'Celkem', 2, 'Kč');

        // Hodnota z poddotazu; chová se jako každý jiný sloupec včetně rozsahového filtru.
        $cm->addNumber('item_count', 'Položek', 0);

        $cm->addDate('created_at', 'Vytvořeno');
    }


    public function buttons(ButtonManager $bm): void
    {
    }


    public function rows(Row $row): void
    {
    }


    public function render(): void
    {
        $this->template->render(__DIR__ . '/SqlJoinGridControl.latte');
    }
}
sql app/Modules/AdminModule/Components/Docs/Data/SqlJoinGridControl/SqlJoinGridControl.sql
SELECT
    o.id AS id,
    o.number AS number,
    CONCAT(c.first_name, ' ', c.last_name) AS customer,
    c.email AS email,
    o.status AS status,
    o.total_price / 100 AS total_price,
    (SELECT COUNT(*) FROM `order_item` oi WHERE oi.id_order = o.id) AS item_count,
    o.created_at AS created_at
FROM `order` o
JOIN `customer` c ON c.id = o.id_customer

Výraz za aliasem

Zákazník je CONCAT(c.first_name, ' ', c.last_name) AS customer. Filtr se poskládá nad výrazem, ne nad aliasem – WHERE CONCAT(…) LIKE ?, protože alias ve WHERE databáze nepovolí. Hledá se tak rovnou v obou jménech.

Počítaný sloupec

Položek je skalární poddotaz – smí stát ve WHERE i v ORDER BY, takže má filtr i řazení jako každý jiný sloupec:

(SELECT COUNT(*) FROM `order_item` oi WHERE oi.id_order = o.id) AS item_count

S GROUP BY to nejde. Filtr by postavil WHERE COUNT(…) = ?, což databáze odmítne. Řešení: skalární poddotaz (jako tady), databázový pohled, nebo takovému sloupci vypnout filtr přes setFilter(null).