Seitenweise Anzeige der vorhandenen Daten

Sobald die Daten zahlreich werden, möchte man diese nicht mehr nur auf einer Seite aufgelistet bekommen, sondern blätterbar – Paginierung nennt das sich so schön. Im Normalfall werden unten Seitenzahlen zum Anklicken angezeigt.

Wir benötigen dafür nun zwei Zahlen. Die Zahl der anzuzeigenden Datensätze und wie viele Datensätze pro Seite angezeigt werden sollen. Für unser Beispiel (was ja bisher nicht viele Datensätze umfasst) werden wir daher erst mal nur 2 Datensätze pro Seite zulassen. Diese Anzahl kann man später aus realistische Zahlen bringen oder sogar vom Nutzer auswählbar machen, wie viele Datensätze pro Seite angezeigt werden sollen. Wir vergeben dies als Variable, damit später einfach änderbar. Variablenname ist $ds_pro_seite.

Diese Angabe können wir ganz am Anfang unseres PHP-Skriptes machen, damit man diese Angabe auch schnell wieder ändern kann.

        $ds_pro_seite = 2;

Zum Auflisten der Paginierung ergänzen wir unseren Code unterhalb der Tabelle:

        $durchgang = 1;
        for ($i = 0; $i < $ds_gesamt; $i=$i+$ds_pro_seite) {
            echo '<a href="?seite='. $i .'">'. $durchgang .'</a> ';
            $durchgang++;
        } 

Jetzt können wir die normale SELECT-Anweisung ohne die Suche angehen:

<?php

        if ($erg = $db->query("SELECT * FROM kontakte")) {
            if ($erg->num_rows) {
                $ds_gesamt = $erg->num_rows;
                $erg->free();
                if ( isset($_GET['seite']) ) {
                    $seite = $_GET['seite'];
                }
                else
                {
                    $seite = 0;
                }
                if ($erg = $db->query("SELECT * FROM kontakte 
                                       LIMIT $seite, $ds_pro_seite ")) {
                    while ($datensatz = $erg->fetch_object()) {
                        $daten[] = $datensatz;
                    }
                }
                $erg->free();
            }
        }

Bei der Ausgabe der Daten für die Suche müssen wir erst die Anzahl der Treffer ermitteln. Da es öfters Probleme bei der Nutzung von num_rows gibt, muss davor store_result() ausgeführt werden. Dann erhalten wir die Anzahl der Treffer!

        $suche->store_result();
        echo "<p>Anzahl: ". $suche->num_rows ."</p>";
        $ds_gesamt = $suche->num_rows;

Jetzt werden wir die prepare-Anweisung entsprechend ändern und über ein LIMIT ergänzen.

        $suche = $db->prepare("SELECT id, vorname, nachname, anmerkung, erstellt 
          FROM kontakte WHERE nachname LIKE ? OR vorname LIKE ? OR anmerkung LIKE ? 
          LIMIT $seite, $ds_pro_seite ");
        $suche->bind_param('sss', $suche_nach,$suche_nach,$suche_nach);
        $suche->execute();

Jetzt funktioniert sowohl für die Anzeige über alle Daten die Paginierung als auch für die durch die Suche eingeschränkte Ausgabe. Allerdings vergisst das Programm die aktuelle ausgewählte Seite. Geht man bei einem Datensatz auf „anzeigen“ und danach wieder zurück, wird die Tabelle wieder ab Seite 1 angezeigt.

Wir sollten also wieder uns Kurzzeitgedächtnis über die SESSIONs anwerfen.

Starten wir bei der Anzeige über alle Daten weg. Hier haben wir schon einen Ansatzpunkt im Code:

                if ( isset($_GET['seite']) ) {
                    $seite = $_GET['seite'];
                }
                else
                {
                    $seite = 0;
                }

Wir haben jetzt folgende Fälle:

  • erster Aufruf: die Variable $seite ist noch nicht gesetzt
  • Aufruf über die Paginierung – es wird über $_GET['seite'] die gewünschte Seite übergeben
  • Wir haben bereits eine Seite ausgewählt und die Anzeige wird aufgerufen (Einzeldatensatz „anzeigen“ und dann wieder „Tabelle anzeigen“.

Der dritte Fall ist bisher noch nicht abgedeckt. Also erstellen wir eine SESSION-Variable mit dem Namen „seite_nr_normal“

Unsere if-Abfrage erweitern wir. Wir setzen die SESSION-Variable, wenn über $_GET['seite'] eine Seitennummer übergeben wurde:

        if ($erg = $db->query("SELECT * FROM kontakte")) {
            if ($erg->num_rows) {
                if ( isset($_GET['seite']) ) {
                    $seite = $_GET['seite'];
                    $_SESSION['seite_nr_normal'] = $_GET['seite'];
                }
                else

Jetzt können wir im else-Bereich davon ausgehen, dass ein Inhalt $_SESSION['seite_nr_normal'] vorliegt, wenn die Paginierung bereits einmal genutzt wurde. Exisitert diese SESSION-Variable noch nicht, handelt es sich um den ersten Aufruf und wir können diese SESSION-Variable auf 0 setzen.

                else
                {
                    if ( ! isset($_SESSION['seite_nr_normal']) ) 
                    {
                        $_SESSION['seite_nr_normal'] = 0;
                        $seite = 0;
                    }
                    else
                    {
                        $seite = $_SESSION['seite_nr_normal'];
                    }

Damit für den Nutzer (und natürlich auch für uns als Programmierer) gleich sichtbar ist, auf welcher Seite wir uns bei der Pagierung befinden, versehen wir diesen Link entsprechend bzw. machen aus dem Link ein span. Damit wir später über CSS ein schönes Design darüberpacken können, vergeben wir gleich eine Klasse <span class="seite_aktuell">.

Wir wissen, dass dir Variable $seite immer auf die gerade genutzte Seitennummer gesetzt ist.

        $durchgang = 1;
        for ($i = 0; $i < $ds_gesamt; $i=$i+$ds_pro_seite) {
            if ( $i == $seite )
            {
                echo '<span class="seite_aktuell">'. $durchgang .'</span> ';
            }
            else
            {
                echo '<a href="?seite='. $i .'">'. $durchgang .'</a> ';
            }
            $durchgang++;
        }

Jetzt müssen wir noch im Bereich der Suche das Gedächtnis aktivieren. Das passiert fast gleich wie bereits bei der Ausgabe aller Daten:

        $suche->execute();
        $suche->store_result();
        echo "<p>Treffer: ". $suche->num_rows ."</p>";
        $ds_gesamt = $suche->num_rows;
        // hier muss die neue SQL-Anweisung rein
                if ( isset($_GET['seite']) ) {
                    $seite = $_GET['seite'];
                    $_SESSION['seite_nr_suche'] = $_GET['seite'];
                }
                else
                {
                    if ( ! isset($_SESSION['seite_nr_suche'])) {
                        $_SESSION['seite_nr_suche'] = 0;
                        $seite = 0;
                    }
                    else
                    {
                        $seite = $_SESSION['seite_nr_suche'];
                    }
                }

Jetzt haben wir allerdings noch den Fall, dass wir während der Suche ein neuer Suchbegriff eingeben. Hat dieser weniger Treffer als der alte Suchbegriff, erhalten wir keine Daten angezeigt, da die anzuzeigende Seite gar nicht existieren kann.

Daher sollten wir bei jeder neuen Suche die Variable $_SESSION['seite_nr_suche'] auf 0 setzen:

if ( $modus_aendern == false ) {
    $daten = array();
    if ( isset($_GET['suchbegriff']) ) {
        $_SESSION['seite_nr_suche'] = 0;
    }

Wollen wir diese Reaktion auch bei der kompletten Anzeige – sprich bei dem Wechsel von der Suche zurück auf die komplette Tabelle durch Klick auf „alle Daten anzeigen“, dann einfach die SESSION-Variable im Aktion-Bereich „allesanzeigen“ auf 0 setzen.

if (isset($_GET['aktion']) and $_GET['aktion'] == 'allesanzeigen') {
    unset($_SESSION['suchbegriff']);
    $_SESSION['seite_nr_normal'] = 0;
}

Und somit haben wir eine komplette Seitenpaginierung integriert, die auch ein Gedächtnis für die letzten Nutzeraktionen hat und wieder die passende Seite anzeigt.

Und jetzt noch die SQL-Anweisung

                        $seite = $_SESSION['seite_nr_suche'];
                    }
                }
        $suche = $db->prepare("SELECT id, vorname, nachname, anmerkung, erstellt 
             FROM kontakte 
             WHERE nachname LIKE ? OR vorname LIKE ? OR anmerkung LIKE ? 
             LIMIT $seite, $ds_pro_seite ");
        $suche->bind_param('sss', $suche_nach,$suche_nach,$suche_nach);
        $suche->execute();

Hier der komplette bisher entstandene Quellcode:

<?php
require 'inc/db.php';
$ds_pro_seite = 2;
if (isset($_GET['aktion']) and $_GET['aktion'] == 'allesanzeigen') {
    unset($_SESSION['suchbegriff']);
    $_SESSION['seite_nr_normal'] = 0;
}
if (isset($_GET['aktion']) and $_GET['aktion'] == 'sicherheitsabfrage') {
    if ( isset($_GET['id'])) {
        $id_einlesen = (INT) $_GET['id'];
        echo '<h1>Sicherheitsabfrage Löschen</h1>';
        echo '<p>Soll der folgende Datensatz unwiderruflich gelöscht werden?</p>';
        echo '<p><a href="?aktion=loeschen&id='. $id_einlesen.'">endgültig löschen!!</a></p>';
        $_GET['aktion'] = 'anzeigen';
    }
}
if (isset($_GET['aktion']) and $_GET['aktion'] == 'anzeigen') {
    if ( isset($_GET['id'])) {
        $id_einlesen = (INT) $_GET['id'];
        if ($id_einlesen > 0) {
            echo "<h1>Daten anzeigen von $id_einlesen</h1>";
            $dseinlesen = $db->prepare("SELECT id, vorname, nachname, anmerkung, erstellt 
                                               FROM kontakte WHERE id = ? ");
            $dseinlesen->bind_param('i', $id_einlesen);
            $dseinlesen->execute();
            $dseinlesen->bind_result($id, $vorname, $nachname, $anmerkung, $erstellt);
            $dseinlesen->fetch();
            echo "<p>ID: <b> $id </b><br>";          
            echo "Vorname: <b> $vorname </b><br>";          
            echo "Nachname: <b> $nachname </b><br>";          
            echo "Anmerkung: <b> $anmerkung </b><br>";          
            echo "erstellt am: <b> $erstellt </b></p>";          
            echo '<p><a href="index.php">Tabelle anzeigen</a>';
            $dseinlesen->close();
            exit;   
        }
    }
}
if (isset($_GET['aktion']) and $_GET['aktion'] == 'loeschen') {
    // löschen von Datensatz
    if (isset($_GET['id'])) {
        $id = (INT) $_GET['id'];
        if ( $id > 0)
        {
            $loeschen = $db->prepare("DELETE FROM kontakte WHERE id=? LIMIT 1");
            $loeschen->bind_param('i', $id);
            if ($loeschen->execute()) {
                echo "<p>Datensatz $id wurde gelöscht</p>";
            }
        }
    }
}
if (isset($_POST['aktion']) and $_POST['aktion']=='speichern' ) {
    $vorname = "";
    if (isset($_POST['vorname'])) {
        $vorname = trim($_POST['vorname']);
    }
    $nachname = "";
    if (isset($_POST['nachname'])) {
        $nachname = trim($_POST['nachname']);
    }
    $anmerkung = "";
    if (isset($_POST['anmerkung'])) {
        $anmerkung = trim($_POST['anmerkung']);
    }
    if ( $vorname != '' or $nachname != '' or $anmerkung != '' ) 
    {
        // speichern
        $einfuegen = $db->prepare("INSERT INTO kontakte
            (vorname, nachname, anmerkung, erstellt)
            VALUES (?, ?, ?, NOW())");
        $einfuegen->bind_param('sss', $vorname, $nachname, $anmerkung);
        if ($einfuegen->execute()) {
            header('Location: index.php?aktion=feedbackgespeichert');
            die();
        }
        echo "<p>Daten werden gespeichert</p>";
    }
}
if (isset($_GET['aktion']) and $_GET['aktion'] == 'feedbackgespeichert') {
    echo '<p class="feedbackerfolgreich">Datensatz wurde gespeichert</p>'; 
}
$modus_aendern = false;
if (isset($_GET['aktion']) and $_GET['aktion'] == 'bearbeiten') {
    $modus_aendern = true;
}
if (isset($_POST['aktion']) and $_POST['aktion'] == 'korrigieren') {
    $id = "";
    if ( isset ($_POST['id'])) {
        $id = (INT) trim($_POST['id']);
    }
    $vorname = "";
    if (isset($_POST['vorname'])) {
        $vorname = trim($_POST['vorname']);
    }
    $nachname = "";
    if (isset($_POST['nachname'])) {
        $nachname = trim($_POST['nachname']);
    }
    $anmerkung = "";
    if (isset($_POST['anmerkung'])) {
        $anmerkung = trim($_POST['anmerkung']);
    }
    if ( $id != '' AND ( $vorname != '' or $nachname != '' or $anmerkung != '')) {
        $update = $db->prepare("UPDATE kontakte SET
                                vorname = ?, nachname = ?, anmerkung = ?
                                WHERE id = ? LIMIT 1");
        $update->bind_param("sssi", $vorname, $nachname, $anmerkung, $id);
        if ( $update->execute() ) {
            echo '<p class="feedbackerfolg">Datensatz wurde geändert</p>';
            $modus_aendern = false;
        }
    }
}
?>
<form action="" method="get">
    suchen nach:
    <input type="hidden" name="aktion" value="suchen">
    <input type="text" name="suchbegriff" id="suchbegriff">
    <input type="submit" value="suchen">
</form>
<?php
if ( $modus_aendern == false ) {
    $daten = array();
    if ( isset($_GET['suchbegriff']) ) {
        $_SESSION['seite_nr_suche'] = 0;
    }
    if ( ! isset($_GET['suchbegriff']) and isset($_SESSION['suchbegriff']) ) 
    {
        $_GET['suchbegriff'] = $_SESSION['suchbegriff'];
    }
    if ( isset($_GET['suchbegriff']) and trim ($_GET['suchbegriff']) != '' )
    {
        $_SESSION['suchbegriff'] = $_GET['suchbegriff'];
        $suchbegriff = trim ($_GET['suchbegriff']);
        echo "<p>Gesucht wird nach: <b>$suchbegriff</b>";
        echo ' - wieder <a href="?aktion=allesanzeigen">alle Daten anzeigen</a>';
        echo "</p>"; 
        $suche_nach = "%{$suchbegriff}%";
        $suche = $db->prepare("SELECT id, vorname, nachname, anmerkung, erstellt 
                 FROM kontakte WHERE nachname LIKE ? OR vorname LIKE ? OR anmerkung LIKE ?");
        $suche->bind_param('sss', $suche_nach,$suche_nach,$suche_nach);
        $suche->execute();
        $suche->store_result();
        echo "<p>Treffer: ". $suche->num_rows ."</p>";
        $ds_gesamt = $suche->num_rows;
        // hier muss die neue SQL-Anweisung rein
                if ( isset($_GET['seite']) ) {
                    $seite = $_GET['seite'];
                    $_SESSION['seite_nr_suche'] = $_GET['seite'];
                }
                else
                {
                    if ( ! isset($_SESSION['seite_nr_suche'])) {
                        $_SESSION['seite_nr_suche'] = 0;
                        $seite = 0;
                    }
                    else
                    {
                        $seite = $_SESSION['seite_nr_suche'];
                    }
                }
        $suche = $db->prepare("SELECT id, vorname, nachname, anmerkung, erstellt 
                 FROM kontakte WHERE nachname LIKE ? OR vorname LIKE ? OR anmerkung LIKE ?
                 LIMIT $seite, $ds_pro_seite
                 ");
        $suche->bind_param('sss', $suche_nach,$suche_nach,$suche_nach);
        $suche->execute();
        // Am Anfang muss noch die Seitenzahl auf 0 gesetzt werden, wenn es ein Wechsel 
        // zwischen suche und normale Anzeige gibt!
        $suche->bind_result($id, $vorname, $nachname, $anmerkung, $erstellt);
        while ($suche->fetch()) {
            $daten[] = (object) array('id' => $id, 
                              'vorname'   => $vorname, 
                              'nachname'  => $nachname, 
                              'anmerkung' => $anmerkung, 
                              'erstellt'  => $erstellt);
        }
        $suche->close();
        $id        = '';
        $vorname   = '';
        $nachname  = '';
        $anmerkung = '';
        $erstellt  = '';
    }
    else
    {
        if ($erg = $db->query("SELECT * FROM kontakte")) {
            if ($erg->num_rows) {
                $ds_gesamt = $erg->num_rows;
                $erg->free();
                if ( isset($_GET['seite']) ) {
                    $seite = $_GET['seite'];
                    $_SESSION['seite_nr_normal'] = $_GET['seite'];
                }
                else
                {
                    if ( ! isset($_SESSION['seite_nr_normal']) ) 
                    {
                        $_SESSION['seite_nr_normal'] = 0;
                        $seite = 0;
                    }
                    else
                    {
                        $seite = $_SESSION['seite_nr_normal'];
                    }
                }
                if ($erg = $db->query("SELECT * FROM kontakte LIMIT $seite, $ds_pro_seite  ")) {
                    while ($datensatz = $erg->fetch_object()) {
                        $daten[] = $datensatz;
                    }
                }
                // echo "<li>". $erg->num_rows;
                // while ($datensatz = $erg->fetch_object()) {
                //     $daten[] = $datensatz;
                // }
                $erg->free();
            }
        }
    }
if ( ! count($daten) ) {
    echo "<p>Es liegen keine Daten vor :(</p>";
} else {
?>
<table>
    <thead>
        <tr>
            <th>Nutzeraktion</th>
            <th>ID</th>
            <th>Vorname</th>
            <th>Nachname</th>
            <th>Anmerkung(en)</th>
            <th>erstellt</th>
        </tr>
    </thead>
    <tbody>
        <?php
        foreach ($daten as $inhalt) {
        ?>
        <tr>
            <td>
                <a href="?aktion=anzeigen&id=<?php echo $inhalt->id; ?>">anzeigen</a> 
                <a href="?aktion=bearbeiten&id=<?php echo $inhalt->id; ?>">ändern</a> 
                <a href="?aktion=sicherheitsabfrage&id=<?php echo $inhalt->id; ?>">löschen</a>
            </td>
            <td><?php echo $inhalt->id; ?></td>
            <td><?php echo bereinigen($inhalt->vorname); ?></td>
            <td><?php echo bereinigen($inhalt->nachname); ?></td>
            <td><?php echo bereinigen($inhalt->anmerkung); ?></td>
            <td><?php echo $inhalt->erstellt; ?></td>
        </tr>
        <?php
        }
        ?>
    </tbody>
</table>
<?php
        echo "<p>Seite: ";
        $durchgang = 1;
        for ($i = 0; $i < $ds_gesamt; $i=$i+$ds_pro_seite) {
            if ( $i == $seite )
            {
                echo '<span class="seite_aktuell">'. $durchgang .'</span> ';
            }
            else
            {
                echo '<a href="?seite='. $i .'">'. $durchgang .'</a> ';
            }
            $durchgang++;
        }
    }
} else {
    echo "<h1>Daten ändern</h1>";
    if ( isset($_GET['id'])) {
        $id_einlesen = (INT) $_GET['id'];
        if ($id_einlesen > 0) {
            $dseinlesen = $db->prepare("SELECT id, vorname, nachname, anmerkung 
                                               FROM kontakte WHERE id = ? ");
            $dseinlesen->bind_param('i', $id_einlesen);
            $dseinlesen->execute();
            $dseinlesen->bind_result($id, $vorname, $nachname, $anmerkung);
            while ($dseinlesen->fetch()) {
                // echo "<li>";
                // echo $id ." / ". $vorname . " ". $nachname;          
            }
        }
    }
}
if ( ! isset($vorname) ) {
    $vorname = '';
}
if ( ! isset($nachname) ) {
    $nachname = '';
}
if ( ! isset($anmerkung) ) {
    $anmerkung = '';
}
?>
<form action="" method="post">
    <p><label>Vorname: 
        <input type="text" name="vorname" id="vorname" value="<?php echo $vorname; ?>">
    </label></p>
    <p><label>Nachname:
        <input type="text" name="nachname" id="nachname" value="<?php echo $nachname; ?>">
    </label></p>
    <p><label>Anmerkung(en):
        <textarea name="anmerkung" id="anmerkung"><?php echo $anmerkung; ?></textarea>
        </label></p>
    <?php    
    if ($modus_aendern != true ) {
        echo '<input type="hidden" name="aktion" value="speichern">';
        echo '<p><input type="submit" value="speichern"></p>';
    }
    else
    {
        echo '<input type="hidden" name="aktion" value="korrigieren">';
        echo '<input type="hidden" name="id" value="'. $id .'">';
        echo '<p><input type="submit" value="ändern"></p>';
    }
    ?>
</form>