JsonSQL Demo: WHERE IN Filter mit JOIN & Alias

🎯 WHERE IN Filter + LEFT JOIN

In dieser Demo filtern wir Produkte anhand gewählter Kategorien.
Die zugehörige Kategorie wird per LEFT JOIN eingeblendet – auch wenn keine passende Kategorie vorhanden ist.

Besonderheit: Unsere JOIN-Funktion unterstützt auch unterschiedlich benannte Felder.
Statt dass in beiden Tabellen die Spalte gleich heißt (z. B. category_id), können wir gezielt angeben, welche Felder verknüpft werden sollen – mit:

->join('st3_categories', ['local' => 'pro_cat_id', 'foreign' => 'cat_id'], 'LEFT')

🔄 local bezeichnet das Feld in der aktuellen Tabelle („Produkte“),
🆚 foreign das Feld in der verknüpften Tabelle („Kategorien“).
Damit funktioniert der JOIN auch dann, wenn die Feldnamen nicht übereinstimmen – z. B. pro_cat_idcat_id.

📁 Kategorien filtern
Zurücksetzen
📦 Gefilterte Produkte
Produkt Kategorie Preis
Produkt 1 Technik 💶 29.40 €
Produkt 10 Technik 💶 24.30 €
Produkt 11 Büro 💶 48.40 €
Produkt 12 Büro 💶 83.20 €
Produkt 13 Freizeit 💶 15.00 €
Produkt 14 Gesundheit 💶 96.90 €
Produkt 15 Gesundheit 💶 59.70 €
Produkt 16 Freizeit 💶 95.20 €
Produkt 17 Gesundheit 💶 59.00 €
Produkt 18 Haushalt 💶 61.70 €
Produkt 19 Technik 💶 15.70 €
Produkt 2 Haushalt 💶 86.20 €
Produkt 20 Haushalt 💶 95.10 €
Produkt 21 Freizeit 💶 23.90 €
Produkt 22 Technik 💶 99.00 €
Produkt 23 Haushalt 💶 78.20 €
Produkt 24 Büro 💶 71.40 €
Produkt 25 Freizeit 💶 55.60 €
Produkt 3 Technik 💶 42.00 €
Produkt 4 Technik 💶 17.10 €
Produkt 5 Technik 💶 30.40 €
Produkt 6 Haushalt 💶 73.00 €
Produkt 7 Technik 💶 96.30 €
Produkt 8 Haushalt 💶 45.70 €
Produkt 9 Haushalt 💶 52.30 €

JsonSQL Datei: st3_categories.json

[
    {
        "cat_id": 1,
        "cat_title": "B\u00fcro"
    },
    {
        "cat_id": 2,
        "cat_title": "Technik"
    },
    {
        "cat_id": 3,
        "cat_title": "Haushalt"
    },
    {
        "cat_id": 4,
        "cat_title": "Freizeit"
    },
    {
        "cat_id": 5,
        "cat_title": "Gesundheit"
    }
]

JsonSQL Datei: st3_products.json

[
    {
        "pro_id": 1,
        "pro_title": "Produkt 1",
        "pro_price": 29.4,
        "pro_cat_id": 2
    },
    {
        "pro_id": 2,
        "pro_title": "Produkt 2",
        "pro_price": 86.2,
        "pro_cat_id": 3
    },
    {
        "pro_id": 3,
        "pro_title": "Produkt 3",
        "pro_price": 42,
        "pro_cat_id": 2
    },
    {
        "pro_id": 4,
        "pro_title": "Produkt 4",
        "pro_price": 17.1,
        "pro_cat_id": 2
    },
    {
        "pro_id": 5,
        "pro_title": "Produkt 5",
        "pro_price": 30.4,
        "pro_cat_id": 2
    },
    {
        "pro_id": 6,
        "pro_title": "Produkt 6",
        "pro_price": 73,
        "pro_cat_id": 3
    },
    {
        "pro_id": 7,
        "pro_title": "Produkt 7",
        "pro_price": 96.3,
        "pro_cat_id": 2
    },
    {
        "pro_id": 8,
        "pro_title": "Produkt 8",
        "pro_price": 45.7,
        "pro_cat_id": 3
    },
    {
        "pro_id": 9,
        "pro_title": "Produkt 9",
        "pro_price": 52.3,
        "pro_cat_id": 3
    },
    {
        "pro_id": 10,
        "pro_title": "Produkt 10",
        "pro_price": 24.3,
        "pro_cat_id": 2
    },
    {
        "pro_id": 11,
        "pro_title": "Produkt 11",
        "pro_price": 48.4,
        "pro_cat_id": 1
    },
    {
        "pro_id": 12,
        "pro_title": "Produkt 12",
        "pro_price": 83.2,
        "pro_cat_id": 1
    },
    {
        "pro_id": 13,
        "pro_title": "Produkt 13",
        "pro_price": 15,
        "pro_cat_id": 4
    },
    {
        "pro_id": 14,
        "pro_title": "Produkt 14",
        "pro_price": 96.9,
        "pro_cat_id": 5
    },
    {
        "pro_id": 15,
        "pro_title": "Produkt 15",
        "pro_price": 59.7,
        "pro_cat_id": 5
    },
    {
        "pro_id": 16,
        "pro_title": "Produkt 16",
        "pro_price": 95.2,
        "pro_cat_id": 4
    },
    {
        "pro_id": 17,
        "pro_title": "Produkt 17",
        "pro_price": 59,
        "pro_cat_id": 5
    },
    {
        "pro_id": 18,
        "pro_title": "Produkt 18",
        "pro_price": 61.7,
        "pro_cat_id": 3
    },
    {
        "pro_id": 19,
        "pro_title": "Produkt 19",
        "pro_price": 15.7,
        "pro_cat_id": 2
    },
    {
        "pro_id": 20,
        "pro_title": "Produkt 20",
        "pro_price": 95.1,
        "pro_cat_id": 3
    },
    {
        "pro_id": 21,
        "pro_title": "Produkt 21",
        "pro_price": 23.9,
        "pro_cat_id": 4
    },
    {
        "pro_id": 22,
        "pro_title": "Produkt 22",
        "pro_price": 99,
        "pro_cat_id": 2
    },
    {
        "pro_id": 23,
        "pro_title": "Produkt 23",
        "pro_price": 78.2,
        "pro_cat_id": 3
    },
    {
        "pro_id": 24,
        "pro_title": "Produkt 24",
        "pro_price": 71.4,
        "pro_cat_id": 1
    },
    {
        "pro_id": 25,
        "pro_title": "Produkt 25",
        "pro_price": 55.6,
        "pro_cat_id": 4
    }
]

<?php
// Seitentitel und Includes
$pageTitle = "JsonSQL Demo: WHERE IN Filter mit JOIN & Alias";

$JsonSQLpath = __DIR__ . '/../../src/JsonSQL.php';
if (!file_exists($JsonSQLpath)) {
    die("❌ Datei nicht gefunden!");
}
require_once $JsonSQLpath;

require_once __DIR__ . '/../includes/header.php';

use Src\JsonSQL;

// JsonSQL-Instanz
$db = new JsonSQL(['demo' => __DIR__ . '/../testdb']);
$db->use('demo');

$categoryTable = 'st3_categories';
$productTable  = 'st3_products';

// Demo-Daten vorbereiten
if (!file_exists(__DIR__ . '/../testdb/' . $categoryTable . '.json')) {
    $db->truncate($categoryTable);
    $cats = ['Büro', 'Technik', 'Haushalt', 'Freizeit', 'Gesundheit'];
    foreach ($cats as $i => $cat) {
        $db->from($categoryTable)->insert([
            'cat_id' => $i + 1,
            'cat_title' => $cat
        ]);
    }
}

if (!file_exists(__DIR__ . '/../testdb/' . $productTable . '.json')) {
    $db->truncate($productTable);
    for ($i = 1; $i <= 25; $i++) {
        $db->from($productTable)->insert([
            'pro_id' => $i,
            'pro_title' => "Produkt $i",
            'pro_price' => rand(100, 1000) / 10,
            'pro_cat_id' => rand(1, 5)
        ]);
    }
}

// Filter aus der URL
$filterIds = isset($_GET['filter']) ? array_map('intval', $_GET['filter']) : [];

// Kategorien laden
$categories = $db->select('*')->from($categoryTable)->orderBy('cat_title')->get();

// Produkte mit JOIN auf Kategorien – jetzt explizit mit unterschiedlichen Spalten
// !Select am Anfang sonst wird der Filter überschrieben !!!
$db->select([
  'pro_title',
  'pro_price',
  'cat_title'])
  ->from($productTable,true)
  ->join($categoryTable, ['local' => 'pro_cat_id', 'foreign' => 'cat_id'], 'LEFT');

if (!empty($filterIds)) {
  $db->where([['pro_cat_id', 'IN', $filterIds]]);
}

// Hier Select würde den Filter resetten und wieder alle Datensätze ausgeben
$products = $db->orderBy('pro_title')
               ->get();


?>

<div class="container">
<h1 class="my-4">🎯 WHERE IN Filter + LEFT JOIN</h1>
<p class="text-muted">
  In dieser Demo filtern wir Produkte anhand gewählter Kategorien.<br>
  Die zugehörige Kategorie wird per <code>LEFT JOIN</code> eingeblendet – auch wenn keine passende Kategorie vorhanden ist.<br><br>

  <strong>Besonderheit:</strong> Unsere JOIN-Funktion unterstützt auch <u>unterschiedlich benannte Felder</u>.<br>
  Statt dass in beiden Tabellen die Spalte gleich heißt (z. B. <code>category_id</code>), 
  können wir gezielt angeben, welche Felder verknüpft werden sollen – mit:
</p>

<pre class="bg-light p-3 rounded">
->join('st3_categories', ['local' => 'pro_cat_id', 'foreign' => 'cat_id'], 'LEFT')
</pre>

<p class="text-muted">
  🔄 <code>local</code> bezeichnet das Feld in der aktuellen Tabelle („Produkte“),<br>
  🆚 <code>foreign</code> das Feld in der verknüpften Tabelle („Kategorien“).<br>
  Damit funktioniert der JOIN auch dann, wenn die Feldnamen nicht übereinstimmen – z. B. <code>pro_cat_id</code> ⇄ <code>cat_id</code>.
</p>


  <div class="row mt-4">
    <div class="col-md-4">
      <div class="card shadow-sm p-3 mb-3">
        <h5 class="card-title">📁 Kategorien filtern</h5>
        <form method="get">
          <?php foreach ($categories as $cat): ?>
            <div class="form-check">
              <input class="form-check-input" type="checkbox" name="filter[]" value="<?= $cat['cat_id'] ?>" id="cat<?= $cat['cat_id'] ?>" <?= in_array($cat['cat_id'], $filterIds) ? 'checked' : '' ?>>
              <label class="form-check-label" for="cat<?= $cat['cat_id'] ?>">
                <?= htmlspecialchars($cat['cat_title']) ?>
              </label>
            </div>
          <?php endforeach; ?>
          <div class="d-flex gap-2 mt-3">
            <button type="submit" class="btn btn-sm btn-primary">Filter anwenden</button>
            <a href="?" class="btn btn-sm btn-outline-secondary">Zurücksetzen</a>
          </div>
        </form>
      </div>
    </div>

    <div class="col-md-8">
      <div class="card shadow-sm p-3">
        <h5 class="card-title">📦 Gefilterte Produkte</h5>
        <?php if (empty($products)): ?>
          <p class="text-muted">Keine Produkte gefunden.</p>
        <?php else: ?>
          <div class="table-responsive">
            <table class="table table-bordered table-striped align-middle">
              <thead class="table-light">
                <tr>
                  <th>Produkt</th>
                  <th>Kategorie</th>
                  <th class="text-end">Preis</th>
                </tr>
              </thead>
              <tbody>
                <?php foreach ($products as $prod): ?>
                  <tr>
                    <td><?= htmlspecialchars($prod['pro_title']) ?></td>
                    <td><?= isset($prod['cat_title']) ? htmlspecialchars($prod['cat_title']) : '<span class="text-muted">keine Kategorie</span>' ?></td>
                    <td class="text-end">💶 <?= number_format($prod['pro_price'], 2) ?> €</td>
                  </tr>
                <?php endforeach; ?>
              </tbody>
            </table>
          </div>
        <?php endif; ?>
      </div>
    </div>
  </div>

  <?php
$scriptName = basename(__FILE__);

// Entferne die Exclude-Tags aus dem Quellcode, aber lasse den eigenen Codeabschnitt aus
$scriptContent = file_get_contents(__FILE__);

// Verhindern, dass der Codeblock selbst ersetzt wird, indem wir ihn in einen temporären Kommentar umwandeln
$scriptContent = preg_replace('//s', '', $scriptContent);

// Hier verwenden wir einen temporären Platzhalter, um den Code zu umgehen, der ersetzt wird.
$scriptContent = str_replace('', '<!-- Exclude End Temp -->', $scriptContent);

?>





<?php
// Vorverarbeitung der Dateien
$jsonCategories = htmlspecialchars(file_get_contents(__DIR__ . '/../testdb/st3_categories.json'));
$jsonProducts   = htmlspecialchars(file_get_contents(__DIR__ . '/../testdb/st3_products.json'));
$phpCode        = htmlspecialchars($scriptContent); // bereits gesetzt
?>





<?php require_once __DIR__ . '/../includes/footer.php'; ?>