Werte an eine Funktion übergeben
Meowsalot
- php
0 pl0 Pit1 Auge0 dedlfix
Hallo alle,
wie ich einen Wert an eine Funktion übergebe ist mir bekannt. Ich möchte allerdings mehrere Werte übergeben die ich zu Beginn nicht kenne bzw. ich nicht weiß wie viele es werden.
Es geht um einen Filter der gesetzt werden kann
<form>
<h3>Kategoriefilter</h3>
<fieldset>
<ul>
<li>
<label>
<input type="checkbox" name="kat" value="1">
Kat 1
</label>
</li>
<li>
<label>
<input type="checkbox" name="kat" value="2">
Kat 2
</label>
</li>
<li>
<label>
<input type="checkbox" name="kat" value="3">
Kat 3
</label>
</li>
</ul>
</fieldset>
<button type="submit" name="action">Filter anwenden </button>
</form>
Aufruf der Funktion im Frontend
<?php $VorlagenAusgabe = Vorlagen($mysqli, $filter); ?>
Die Funktion an sich
function Vorlagen($mysqli, $filter) {
$stmt = $mysqli->prepare("SELECT id, datei, titel, format, kategorie, vk_titel FROM vorlagen
LEFT JOIN vorlagen_kategorie ON vorlagen_kategorie.vk_id = vorlagen.kategorie
WHERE kategorie=? ");
$stmt->bind_param("s", $filter);
$stmt->execute();
$stmt->bind_result($id, $datei, $titel, $format, $kategorie, $vk_titel);
$stmt->store_result();
if($stmt->num_rows() > 0) {
while ($stmt->fetch()){
$Vorlagen[] = array(
'id' => $id,
'datei' => $datei,
'titel' => $titel,
'format' => $format,
'kategorie' => $kategorie,
'vk_titel' => $vk_titel
);
}
return $Vorlagen;
}
Bis bald!
Meowsalot (Bernd)
Zeig mal create table;
Hallo pl,
ich weiß zwar nicht für was die wichtig sein soll, aber bitteschön
CREATE TABLE `vorlagen_kategorie` (
`vk_id` int(11) NOT NULL,
`vk_titel` varchar(200) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `vorlagen` (
`id` int(11) NOT NULL,
`datei` varchar(200) NOT NULL,
`titel` varchar(100) NOT NULL,
`format` varchar(10) NOT NULL,
`kategorie` varchar(200) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Bis bald! Meowsalot (Bernd)
hi,
ich weiß zwar nicht für was die wichtig sein soll, aber bitteschön
CREATE TABLE `vorlagen_kategorie` ( `vk_id` int(11) NOT NULL, `vk_titel` varchar(200) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `vorlagen` ( `id` int(11) NOT NULL, `datei` varchar(200) NOT NULL, `titel` varchar(100) NOT NULL, `format` varchar(10) NOT NULL, `kategorie` varchar(200) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Dein Form liefert kat numerisch, ich nehme an das soll ins Feld kategorie. Das ist vom Datentyp her unstimmig aber das nur nebenbei. Vielleicht willst Du die Nummern auch aneinanderreihen…
Wichtiger ist jedoch: Du definierst NOT NULL ohne einen Default festgelegt zu haben. Das bedeutet, daß Dein Code sicherstellen muss, daß da immer ein Wert vorhanden ist für insert/update auf dieses Feld. Infolgedessen muss Deine Funktion diesen Default sicherstellen und das kannst Du schon in der Argumentenliste festlegen.
MfG
Hallo pl,
kann es sein dass du mich falsch verstanden hast? Es geht hier weder um ein Insert noch um ein Update. Dieses funktioniert bei mir.
Ich möchte dem User ein Filter anbieten so dass er nicht alles sieht/sehen muss.
Bis bald!
Meowsalot (Bernd)
hi,
kann es sein dass du mich falsch verstanden hast?
Ja hab ich auch grad gesehen. Aber: Meine Ausführungen zum Default sind bei einer Abfrage ebenso sinngemäß gültig. Denn Dein $filter beruht auf einer Benutzereingabe. D.h., daß Du alle Fälle abdecken musst.
MfG
Hallo alle,
wie ich einen Wert an eine Funktion übergebe ist mir bekannt. Ich möchte allerdings mehrere Werte übergeben die ich zu Beginn nicht kenne bzw. ich nicht weiß wie viele es werden.
Und warum übergibst Du kein Array?
Pit
Hallo Pit,
Und warum übergibst Du kein Array?
meinst du so?
<form method="post">
<h3>Kategoriefilter</h3>
<fieldset>
<ul>
<li>
<label>
<input type="checkbox" name="kat[]" value="u1">
User 1
</label>
</li>
<li>
<label>
<input type="checkbox" name="kat[]" value="u2">
User 2
</label>
</li>
<li>
<label>
<input type="checkbox" name="kat[]" value="u3">
User 3
</label>
</li>
</ul>
</fieldset>
<button type="submit" name="action">Filter anwenden </button>
</form>
$kat = array();
$kat = $_POST["kat"];
$VorlagenAusgabe = Vorlagen($mysqli, $kat);
Bis bald!
Meowsalot (Bernd)
Wenn Du mehrere Werte filtern willst, müsste Deine Abfrage anders aussehen. Überlege ob UND//ODER Verknüpfung.
MfG
Hallo pl,
in meinem Fall wäre das AND richtig? Denn mit OR sage ich nimm das eine oder das andere? Ich möchte ja genau die haben, die der User anklickt.
Bis bald! Meowsalot (Bernd)
hi
in meinem Fall wäre das AND richtig? Denn mit OR sage ich nimm das eine oder das andere? Ich möchte ja genau die haben, die der User anklickt.
Dann entscheidet der User ob UND//ODER ganz einfach 😉
Machn Feld zum Ankreuzen. MfG
Hallo
wie ich einen Wert an eine Funktion übergebe ist mir bekannt. Ich möchte allerdings mehrere Werte übergeben die ich zu Beginn nicht kenne bzw. ich nicht weiß wie viele es werden.
Zauberwort des Tages: Array
Es geht um einen Filter der gesetzt werden kann
<form> <h3>Kategoriefilter</h3> <fieldset> <ul> <li> <label> <input type="checkbox" name="kat" value="1"> Kat 1 </label> </li> <li> <label> <input type="checkbox" name="kat" value="2"> Kat 2 </label> </li> <li> <label> <input type="checkbox" name="kat" value="3"> Kat 3 </label> </li> </ul> </fieldset> <button type="submit" name="action">Filter anwenden </button> </form>
Da keine Methode für das Formular gesetzt ist, steht die Methode, mit der die Daten ins Skript kommen, nicht fest. Du wirst die Werte der aktivierten Checkboxen in $_REQUEST['kat']
finden, besser wäre aber die Festlegung des Formulars auf GET oder POST und das Auslesen im PHP-Skript mkit $_GET['kat']
oder $_POST['kat']
. Bau dir eine Kontrollausgabe mit print_r
oder var_dump
für $_REQUEST
, $_GET
oder $_POST
in das Skript, damit du siehst, was in welcher Struktur hereinkommt.
Aufruf der Funktion im Frontend
<?php $VorlagenAusgabe = Vorlagen($mysqli, $filter); ?>
Du kannst mit PHP das Frontend erzeugen, aber PHP ist selbst nicht Frontend.
Tschö, Auge
Hallo Auge,
Zauberwort des Tages: Array
dieses habe ich hier eingebaut:
https://forum.selfhtml.org/self/2018/mar/22/werte-an-eine-funktion-uebergeben/1716956#m1716956
Da keine Methode für das Formular gesetzt ist, steht die Methode, mit der die Daten ins Skript kommen, nicht fest. Du wirst die Werte der aktivierten Checkboxen in
$_REQUEST['kat']
finden, besser wäre aber die Festlegung des Formulars auf GET oder POST und das Auslesen im PHP-Skript mkit$_GET['kat']
oder$_POST['kat']
.
Ich habe mich für POST entschieden, sieht schöner aus und es steht nicht so viel in der URL oder sollte man für einen Filter lieber GET nehmen?
method="post"
Bau dir eine Kontrollausgabe mit
print_r
odervar_dump
für$_REQUEST
,$_GET
oder$_POST
in das Skript, damit du siehst, was in welcher Struktur hereinkommt.
Habe ich
var_dump($kat);
Jetzt erhalte ich
array(2) { [0]=> string(2) "u1" [1]=> string(2) "u2" }
Die Frage ist, wie verarbeite ich dieses in meiner Funktion?
Bis bald!
Meowsalot (Bernd)
hi,
Die Frage ist, wie verarbeite ich dieses in meiner Funktion?
Was steht denn im Feld? Mit Sicherheit ein Einzelwert. Wenn das über eine Stringverkettung von Einzelwerten die das Form liefert matchen soll, müssen diese Werte in der Tabelle entsprechend auch aussehen. Oder anders ausgedrückt: Liefert das Form 123
wird das nie einen Treffer geben wenn im Feld kategorie nur 1, 2, oder 3 steht.
Was steht denn da drin bei Dir?
Hallo
Da keine Methode für das Formular gesetzt ist, steht die Methode, mit der die Daten ins Skript kommen, nicht fest. Du wirst die Werte der aktivierten Checkboxen in
$_REQUEST['kat']
finden, besser wäre aber die Festlegung des Formulars auf GET oder POST und das Auslesen im PHP-Skript mkit$_GET['kat']
oder$_POST['kat']
.Ich habe mich für POST entschieden, sieht schöner aus und es steht nicht so viel in der URL oder sollte man für einen Filter lieber GET nehmen?
Falls das ein Filter sein soll, der eventuell in Links benutzt werden können soll, solltest du GET benutzen. „Saubere URL“ hin oder her, mit einem URL Parameter lässt sich solch ein Filter „nachbauen“. Da dein Fall aber danach aussieht, diese Werte auf dem Server abzuspeichern, ist POST die bei Weitem bessere Wahl. Mit GET könnte man eine ungewollte Änderung auslösen, indem man eine URL mit den gewünschten Werten erstellt und die URL einfach im Browser lädt. Das ist im Allgemeinen nicht wünschenswert. Also: POST.
… eine Kontrollausgabe mit
print_r
odervar_dump
…Habe ich
var_dump($kat);
Woher kommt $kat
?
Jetzt erhalte ich
array(2) { [0]=> string(2) "u1" [1]=> string(2) "u2" }
Das passt aber nicht z den Werten deines HTML-Codebeispiels (1, 2, 3).
Die Frage ist, wie verarbeite ich dieses in meiner Funktion?
Indem du $_POST['kat']
als Parameter an die Funktion und dort drinnen in einer Schleife an den Query übergibst.
Tschö, Auge
Hallo Auge,
Falls das ein Filter sein soll, der eventuell in Links benutzt werden können soll, solltest du GET benutzen. „Saubere URL“ hin oder her, mit einem URL Parameter lässt sich solch ein Filter „nachbauen“.
Ok, wie hier geschrieben nehme ich für den Filter GET https://forum.selfhtml.org/self/2018/mar/22/werte-an-eine-funktion-uebergeben/1716967#m1716967
Da dein Fall aber danach aussieht, diese Werte auf dem Server abzuspeichern, ist POST die bei Weitem bessere Wahl.
Davon habe ich nie etwas geschrieben. Ich möchte nichts speichern, ich möchte nur eine Ausgabe filtern. Die werte stehen bereits in der Datenbank
Woher kommt
$kat
?
Daher
$kat = array();
$kat = $_GET["kat"];
Das passt aber nicht z den Werten deines HTML-Codebeispiels (1, 2, 3).
Ich hatte die Boxen in der Zwischenzeit geändert
https://forum.selfhtml.org/self/2018/mar/22/werte-an-eine-funktion-uebergeben/1716956#m1716956
Indem du
$_POST['kat']
als Parameter an die Funktion und dort drinnen in einer Schleife an den Query übergibst.
In einer Funktion kann man auch mit Schleifen arbeiten?
In einer Funktion kann man auch mit Schleifen arbeiten?
Kann man, muss man aber nicht. Weil man das Ergebnis mit einer zweckmäßigen Abfrage bekommt ohne daß man dafür die ganze Tabelle durchgehen muss.
Dein Filter läuft auf eine UND//ODER Verknüfung der Kategoriekriterien in der where Klause hinaus.
MfG
Hallo pl,
Dein Filter läuft auf eine UND//ODER Verknüfung der Kategoriekriterien in der where Klause hinaus.
mit UND//ODER meinst du folgendes:
Hier noch ein Bild wie meine Einträge aussschauen
Bis bald! Meowsalot (Bernd)
hi,
Dein Filter läuft auf eine UND//ODER Verknüfung der Kategoriekriterien in der where Klause hinaus.
mit UND//ODER meinst du folgendes:
- Wenn nichts gewählt ist, dann werden alle Einträge angezeigt
- Wenn eine oder mehrere checkboxen angeklickt wurden, dann nimm die, die aus der gewählten Kategorie
Nein. UND meint: Zeige mit alle Datensätze die der Kategorie 1 UND 2 UND 3
entsprechen. Sieht das Dein Design überhaupt vor?
ODER hingegen meint: Zeige alle Datenätze die der Kategorie 1 ODER 2 ODER 3
genügen. Da sollte schonmal zumindest 'ne Zeile kommen 😉
Hier noch ein Bild wie meine Einträge aussschauen
Wo ist denn da die Kategorie? Wenn da eine 4 steht, gibt eine Abfrage auf 3 niemals einen Treffer.
MfG
Hallo pl,
Nein. UND meint: Zeige mit alle Datensätze die der Kategorie
1 UND 2 UND 3
entsprechen. Sieht das Dein Design überhaupt vor?ODER hingegen meint: Zeige alle Datenätze die der Kategorie
1 ODER 2 ODER 3
genügen. Da sollte schonmal zumindest 'ne Zeile kommen 😉
Nein dann darf es das ODER nicht geben. Denn ich möchte ja erreichen dass genau die Kategorien ausgelesen werden die der User angeklickt hat, also immer UND?
Wo ist denn da die Kategorie? Wenn da eine 4 steht, gibt eine Abfrage auf 3 niemals einen Treffer.
die letzte spalte ist die Kategorie. Was ist daran so schlimm wenn der User die Kat 3 wählt? Da sind dann eben keine Einträge vorhanden.
Bis bald!
Meowsalot (Bernd)
hi,
Nein dann darf es das ODER nicht geben. Denn ich möchte ja erreichen dass genau die Kategorien ausgelesen werden die der User angeklickt hat, also immer UND?
Wenn ich Dein DB Design richtig verstehe, kann eine Kategorie mehrere Vorlagen haben. Also eine 1:n Beziehung Kategorie:Vorlage
die letzte spalte ist die Kategorie. Was ist daran so schlimm wenn der User die Kat 3 wählt? Da sind dann eben keine Einträge vorhanden.
Das ist ok, n kann ja auch 0 sein. Also zu einer bestimmten Kategorie keine Vorlage(n).
Nun wählt ein User 2 UND 4. Da nehme ich an, daß er alle Vorlagen sehen will die entweder der Kategorie 2 ODER der Kategorie 4 angehören. Wenn das so sein soll ist es im SQL Statement eine ODER Verknüpfung.
MFG
Hallo
Da dein Fall aber danach aussieht, diese Werte auf dem Server abzuspeichern, ist POST die bei Weitem bessere Wahl.
Davon habe ich nie etwas geschrieben. Ich möchte nichts speichern, ich möchte nur eine Ausgabe filtern. Die werte stehen bereits in der Datenbank
Ah ja, SELECT
, also keine Speicherung.
Indem du
$_POST['kat']
als Parameter an die Funktion und dort drinnen in einer Schleife an den Query übergibst.In einer Funktion kann man auch mit Schleifen arbeiten?
Ja, kann man.
Tschö, Auge
Tach!
Ich habe mich für POST entschieden, sieht schöner aus und es steht nicht so viel in der URL oder sollte man für einen Filter lieber GET nehmen?
Schönheit sollte hier nicht das Kriterium sein, sondern die Funktion. In die Adresszeile schaut niemand, um dort Schönheit zu sehen. Der Vorteil der Parameter in der URL ist, dass man diese Abfrage wiederholt laufen lassen kann. Sei es mit F5 ohne Warnung, dass POST-Daten wiederholt werden oder aus einem Bookmark heraus.
Generell kann man die Frage nach POST vs. GET so beantworten, dass für Datenänderungen (Anlegen, Ändern, Löschen) POST und für Datenabfragen GET zuständig ist.
dedlfix.
Hallo dedlfix,
Generell kann man die Frage nach POST vs. GET so beantworten, dass für Datenänderungen (Anlegen, Ändern, Löschen) POST und für Datenabfragen GET zuständig ist.
Ok, dann hat sich das Thema URL Schönheit erledigt, ich nehme GET.
Meine URL
/moin.php?kat%5B%5D=u1&kat%5B%5D=u2&kat%5B%5D=u3&action=
Woher die vielen % kommen kann ich dir nicht sagen. Die Ausgabe stimmt wieder
array(3) { [0]=> string(2) "u1" [1]=> string(2) "u2" [2]=> string(2) "u3" }
Bis bald! Meowsalot (Bernd)
Tach!
Meine URL
/moin.php?kat%5B%5D=u1&kat%5B%5D=u2&kat%5B%5D=u3&action=
Woher die vielen % kommen kann ich dir nicht sagen. Die Ausgabe stimmt wieder
Das sind die []-Klammern in URL-Kodierung. Die sind technisch notwendig, die Browser zeigen diese Zeichen aber oftmals direkt an.
dedlfix.
Hallo dedlfix,
danke für die Info! Also muss ich dieses nicht weiter berücksichtigen?
Bis bald! Meowsalot (Bernd)
Tach!
wie ich einen Wert an eine Funktion übergebe ist mir bekannt. Ich möchte allerdings mehrere Werte übergeben die ich zu Beginn nicht kenne bzw. ich nicht weiß wie viele es werden.
Dann nimmt man ein Array.
Es geht um einen Filter der gesetzt werden kann
Formuliere doch bitte (auch) aus der Sicht des Programms, nicht (nur) aus der Sicht des Anwenders. Filter heißt in deinem Fall, dass es Checkboxen sind, die deren Werte du übertragen möchtest?
Das erste ist, die Werte mehrere Input-Felder mit gleichem Namen ins PHP zu bekommen. PHP sieht dazu vor, []
an den Namen anzuhängen. Dann hast du ein Array im $_POST für diesen Namen.
$stmt = $mysqli->prepare("SELECT id, datei, titel, format, kategorie, vk_titel FROM vorlagen LEFT JOIN vorlagen_kategorie ON vorlagen_kategorie.vk_id = vorlagen.kategorie WHERE kategorie=? "); $stmt->bind_param("s", $filter);
Das Array bekommst du aber nicht in dieser Form in das Statement. Vermutlich willst du auch WHERE kategorie IN (1,3)
haben, also dass in dem Beispielfall 1 oder 3 in der kategorie stehen kann. Oder ist das Feld nicht normalisiert und es steht eine kommaseparierte Liste drin? Es wird schon mit dem IN() nicht einfach, aber damit wird es noch komplexer. Also erstmal: was soll's denn werden?
dedlfix.
Hallo dedlfix,
Dann nimmt man ein Array.
habe ich bereits. Diese Thema ist daher abgeschlossen.
Formuliere doch bitte (auch) aus der Sicht des Programms, nicht (nur) aus der Sicht des Anwenders. Filter heißt in deinem Fall, dass es Checkboxen sind, die deren Werte du übertragen möchtest?
Aus der Sicht des Programms:
Ich nehme die Werte die du mir in $filter übergeben hast, sprich das Array(). Jetzt schaue ich in die Spalte kategorie und gehe die Tabelle von oben nach unten durch. Sobald ein Wert auftaucht den du mir gegeben hast lese ich diese Spalte aus.
Das Array bekommst du aber nicht in dieser Form in das Statement. Vermutlich willst du auch
WHERE kategorie IN (1,3)
haben, also dass in dem Beispielfall 1 oder 3 in der kategorie stehen kann. Oder ist das Feld nicht normalisiert und es steht eine kommaseparierte Liste drin? Es wird schon mit dem IN() nicht einfach, aber damit wird es noch komplexer. Also erstmal: was soll's denn werden?
Auge meinte ich kann diesen Durchlauf mit einer Schleife machen?
https://forum.selfhtml.org/self/2018/mar/22/werte-an-eine-funktion-uebergeben/1716964#m1716964
Bis bald!
Meowsalot (Bernd)
Tach!
Auge meinte ich kann diesen Durchlauf mit einer Schleife machen?
https://forum.selfhtml.org/self/2018/mar/22/werte-an-eine-funktion-uebergeben/1716964#m1716964
Ja, nein, first things first. Wenn ich den Screenshot richtig deute, hast du in dem kategorie-Feld einen einzelnen Wert steht, keine Liste oder oder sowas. Ich gehe mal vom Einzelwert aus. Dann sagtest du, dass du UND haben möchtest, aber das geht nicht. Ein Datensatz kann nicht 1 UND 2 in dem Feld stehen haben. Du willst also tatsächlich die Datensätze in der Ausgabe haben, die da 1 ODER 2 stehen haben. Das lässt sich mit dem IN() abbilden, also WHERE kategorie IN (1,2).
Und jetzt kommt das Problem, dass man auch mit Auges Schleife nicht besonders schön lösen kann. Generell müsstest du ein SQL Statement erstellen, das für jeden Wert im Array ein ?
hat. Bei zweien wäre das also IN (?,?)
Und dann musst du auch zwei Variablen binden. Das können auch Felder eines Arrays sein. Hier bist du mir mysqli im Nachteil gegenüber PDO, weil mysqli immer einzeln binden möchte, PDO aber auch ein Array beliebiger Größe im execute() nimmt. Das Problem mit den ? bleibt aber bei beiden gleich.
dedlfix.
Hallo dedlfix,
danke für deine sehr ausführliche Erklärung. Ich sag es jetzt mal aus meiner Sicht. $filter ist ja ein Array, dort stehen die Kategorien drin, die der User angeklickt hat. Kann man diesen Wert nicht in WHERE kategorie IN ($filter) nehmen? Wenn nicht, könnte man $filter innerhalb der Funktion so umbauen, dass er diese Werte so hat, wie IN diesen braucht?
Bis bald! Meowsalot (Bernd)
Tach!
danke für deine sehr ausführliche Erklärung. Ich sag es jetzt mal aus meiner Sicht. $filter ist ja ein Array, dort stehen die Kategorien drin, die der User angeklickt hat. Kann man diesen Wert nicht in WHERE kategorie IN ($filter) nehmen? Wenn nicht, könnte man $filter innerhalb der Funktion so umbauen, dass er diese Werte so hat, wie IN diesen braucht?
Nein, geht beides nicht im Zusammenhang mit Prepared Statement. Jeder Wert muss da einzeln angegeben und übertragen werden.
dedlfix.
Hallo dedlfix,
das heißt ich kann mein Vorhaben knicken?
Da fällt mir gerade noch etwas ein, kann ich es nicht so in etwa aufbauen?
for($i=0; $i < count($kat); $i++) {
echo "AND kategorie=? ";
}
Und dieses dann nach WHERE kategorie=? dranhängen? IN muss ich ja nicht zwangsläufig benutzen?
Bis bald!
Meowsalot (Bernd)
Hallo,
ich habe hier etwas gefunden nur ich verstehe es nicht so recht. Komme ich damit weiter? https://stackoverflow.com/questions/6053239/mysqli-bind-param-with-an-array-for-in
Bis bald! Meowsalot (Bernd)
Tach!
das heißt ich kann mein Vorhaben knicken?
Ganz knicken muss nicht, es geht nur komplizierter als MySQL einfach ein Array hinzuwerfen. Aber das hast du ja im andren Teilzweig bereits bemerkt.
Da fällt mir gerade noch etwas ein, kann ich es nicht so in etwa aufbauen?
for($i=0; $i < count($kat); $i++) { echo "AND kategorie=? "; }
So geht das auch, aber mit OR nicht AND.
Lass dich mal von dem AND-OR-Problem nicht verwirren. Sprachlich gesehen geht beides, aber es kommt drauf an, von wo aus man die Angelegenheit betrachtet. Von oben gesehen möchtest du die Datensätze mit dem Wert X und die mit dem Wert Y. Aber so eine Datenbank arbeitet da etwas anders. Die betrachtet jeden Datensatz einzeln und muss nur für diesen einen entscheiden, ob die Bedingung passt, bevor sie das Spielchen beim nächsten fortsetzt. An der Stelle heißt es also: "nimm den Datensatz, wenn der Wert X oder wenn er Y ist".
dedlfix.
Hallo,
ich sehe zwei Möglichkeiten.
#1. Schleife
Man prepared das Statement so wie es ist, und zwar zu Beginn der Funktion. Den bind_param macht man an eine Temp-Variable (muss in mysqli so sein), und man bereitet ein leeres Array zum Sammeln der Ergebnisse vor.
Dann durchläuft man das $filter-Array, weist nacheinander jeden Wert darin dieser Temp-Variablen zu, führt das Statement aus und hängt die Ergebnisse an das Sammel-Array an.
Vorteil: Man hat nur ein Statement zu preparen, und die DB kann den Plan dafür gut cachen.
Nachteil: Man muss pro Checkbox einen DB-Roundtrip machen.
#2. Dynamisches SQL
Das ist sehr mühsam, wenn man prepare verwendet. Hier wäre wohl ein Einsatz ohne Prepare besser.
Man bestimmt die Länge des $filter-Array und produziert die WHERE-Bedingung dynamisch. Und zwar so, dass man die Array-Einträge SQL-gerecht transformiert (d.h. die Werte in Hochkomma setzen und passend escapen), und dann mit ", " als $glue (->Doku) implodiert. Das Ergebnis setzt man in die Klammern eines IN Ausdrucks, so dass da nachher z.B. WHERE kategorie IN ('1', '5')
steht.
Vorteil: Nur ein DB-Roundtrip
Nachteil: Man muss das SQL zurechtfummeln, wie in schlechten alten mysql-Zeiten.
--
Was in den mir bekannten SQL Servern NICHT funktioniert, ist ein prepared statement mit `WHERE kategorie in (?) und einem Array für den ? Parameter. Aber vielleicht ist MySQL hier mal wieder großzügiger...
Rolf
Hallo Rolf,
auch dir danke für deine Erklärung. Zum Thema schleifen, meinst du vielleicht so?
function Vorlagen($mysqli) {
$values = array('2');
$s = substr( str_repeat( ' , ?' , count( $values ) ) , 2 );
$stmt = $mysqli->prepare('SELECT id, datei, titel, format, kategorie, vk_titel FROM vorlagen
LEFT JOIN vorlagen_kategorie ON vorlagen_kategorie.vk_id = vorlagen.kategorie
WHERE kategorie IN (' . $s . ') ');
$typeDefinitions = str_repeat( 's' , count( $values ) );
$params = array( $typeDefinitions );
foreach ( $values as $k => $v ) {
${ 'varvar' . $k } = $v;
$params[] = &${ 'varvar' . $k };
}
call_user_func_array( array( $stmt , 'bind_param' ) , $params );
$stmt->execute();
$stmt->bind_result($id, $datei, $titel, $format, $kategorie, $vk_titel);
$stmt->store_result();
if($stmt->num_rows() > 0) {
while ($stmt->fetch()){
$Vorlagen[] = array(
'id' => $id,
'datei' => $datei,
'titel' => $titel,
'format' => $format,
'kategorie' => $kategorie,
'vk_titel' => $vk_titel
);
}
return $Vorlagen;
}
}
die Ausgabe stimmt. Jetzt bleibt nur noch die Frage wie bekomme ich in meinem Arry
$kat = array();
$kat = $_GET["kat"];
bei $kat das letzte , weg? Meine Idee war
substr($kat, 0, -2);
Da wird aber gemeckert
Warning: substr() expects parameter 1 to be string, array given in
Bis bald! Meowsalot (Bernd)
Hallo,
so funktioniert es
$kat = array();
$kat = $_GET["kat"];
echo "<pre>";
var_dump($kat);
echo "</pre>";
function Vorlagen($mysqli, $kat) {
//$values = array('1','2');
$values = $kat;
$s = substr( str_repeat( ' , ?' , count( $values ) ) , 2 );
$stmt = $mysqli->prepare('SELECT id, datei, titel, format, kategorie, vk_titel FROM vorlagen
LEFT JOIN vorlagen_kategorie ON vorlagen_kategorie.vk_id = vorlagen.kategorie
WHERE kategorie IN (' . $s . ') ');
$typeDefinitions = str_repeat( 's' , count( $values ) );
$params = array( $typeDefinitions );
foreach ( $values as $k => $v ) {
${ 'varvar' . $k } = $v;
$params[] = &${ 'varvar' . $k };# provide references
}
call_user_func_array( array( $stmt , 'bind_param' ) , $params );
$stmt->execute();
$stmt->bind_result($id, $datei, $titel, $format, $kategorie, $vk_titel);
$stmt->store_result();
if($stmt->num_rows() > 0) {
while ($stmt->fetch()){
$Vorlagen[] = array(
'id' => $id,
'datei' => $datei,
'titel' => $titel,
'format' => $format,
'kategorie' => $kategorie,
'vk_titel' => $vk_titel
);
}
return $Vorlagen;
}
}
Die Ausgabe dann so
<?php $VorlagenBereiche = Vorlagen($mysqli, $kat); ?>
<?php if($VorlagenBereiche > 0) {?>
<?php foreach($VorlagenBereiche as $array){ ?>
<?php echo htmlspecialchars($array['datei']); ?><br>
<?php } }
?>
Das dazugehörige HTML
<form method="get">
<h3>Kategoriefilter</h3>
<fieldset>
<ul>
<li>
<label>
<input type="checkbox"
name="kat[]"
value="1" <?php echo (in_array("1",$kat) ?'checked="checked"':NULL) ?>>
User 1
</label>
</li>
<li>
<label>
<input type="checkbox"
name="kat[]"
value="2" <?php echo (in_array("2",$kat) ?'checked="checked"':NULL) ?>>
User 2
</label>
</li>
<li>
<label>
<input type="checkbox"
name="kat[]"
value="3" <?php echo (in_array("3",$kat) ?'checked="checked"':NULL) ?>>
User 3
</label>
</li>
<li>
<label>
<input type="checkbox"
name="kat[]"
value="4" <?php echo (in_array("4",$kat) ?'checked="checked"':NULL) ?>>
User 4
</label>
</li>
</ul>
</fieldset>
<button type="submit" name="action">Filter anwenden </button>
</form>
Was sagt ihr dazu?
Bis bald!
Meowsalot (Bernd)
Tach!
$kat = array(); $kat = $_GET["kat"]; function Vorlagen($mysqli, $kat) {
Du kannt die $kat schenken und gleich $_GET["kat"] an die Funktion übergeben.
Der Rest ist nicht schön, aber das liegt daran, dass mysqli hier sehr unflexibel ist. Mit PDO brauchst du die Verrenkungen mit dem Binden und dem Bilden der Referenz nicht durchzuführen. Wenn du kannst, steig lieber auf das verwenderfreundlichere PDO um.
dedlfix.
Hallo dedlfix,
Der Rest ist nicht schön, aber das liegt daran, dass mysqli hier sehr unflexibel ist. Mit PDO brauchst du die Verrenkungen mit dem Binden und dem Bilden der Referenz nicht durchzuführen. Wenn du kannst, steig lieber auf das verwenderfreundlichere PDO um.
kann man PDO und mysqli mischen? Bei den neuen Sachen nehmen ich PDO und bei den alten bleibt es erst einmal bei mysqli, geht das?
Bis bald! Meowsalot (Bernd)
Tach!
kann man PDO und mysqli mischen? Bei den neuen Sachen nehmen ich PDO und bei den alten bleibt es erst einmal bei mysqli, geht das?
Du kannst beides gleichzeitig in einem Projekt oder auch einem Script verwenden, Aber du musst die Vorgänge in sich abgeschlossen halten. Also mit mysqli präparieren und mit PDO das Execute durchführen, das geht beispielsweise nicht.
dedlfix.
Hallo Bernd,
nein, den Begriff "Schleife" hatte ich anders gemeint. Ich verkürze deine Statements mal etwas, und zeige Dir auch, wie Du ohne die Fetch-Schleife auskommst. Das folgende Beispiel führt pro Eintrag in $kategorien eine DB-Query durch und sammelt mit array_merge
alles in $vorlagen zusammen. Fehler werden geprüft und mit einer Exception behandelt. D.h. du musst um den Aufruf von Vorlagen einen try/catch Block legen, aber dafür hast Du einen definierten Weg, wie Du Fehlermeldungen aus der Funktion hinausbekommst ohne dafür den Returncode umdeuten zu müssen.
Beachte, dass ich den Bind VOR der Schleife mache und auch kein & hinschreibe - das wäre PHP4 Style (oder sogar 3?) und ist heute falsch. Wenn eine Funktion ihre Parameter als Referenz empfängt, erzeugt PHP die Referenz beim Aufruf implizit. Ich will diese Lösung nicht als "besser" darstellen; Nachteile hatte ich schon genannt. Ich schreibe sie nur auf damit Du weißt was ich gemeinte hatte.
function Vorlagen($mysqli, $kategorien) {
$vorlagen = [];
if (!$stmt = $mysqli->prepare("SELECT ... WHERE kategorie = ?"))
throw new Exception("Prepare fehlgeschlagen: ".$mysqli->error);
$kat = "";
if (!$stmt->bind_param("s", $kat) { // Kein & in den Aufruf!
throw new Exception("Bind fehlgeschlagen ".$mysqli->error);
foreach ($kategorien as $kat) {
if (!$stmt->execute())
throw new Exception("execute fehlgeschlagen ".$mysqli->error);
$result = $stmt->get_result();
if ($result === FALSE)
throw new Exception("get_result fehlgeschlagen ".$mysqli->error);
$rows = $result->fetch_all(MYSQLI_ASSOC);
$result->free(); // WICHTIG!
if (is_array($rows))
$vorlagen = array_merge($vorlagen, $rows);
}
return $vorlagen;
}
Die Variante mit flexiblem Binding - RESPEKT!. Den call_user_func_array wollte ich Dir nicht zumuten, aber da habe ich deine PHP-Kenntnisse falsch eingeschätzt. Ein paar Tipps dazu:
Fragezeichenliste ohne substr:
// Dein Code
$s = substr( str_repeat( ' , ?' , count( $values ) ) , 2 );
// Zwei Alternativen dazu:
$s = '?' . str_repeat( ', ?' , count( $values ) - 1 );
$s = implode(',', array_fill(0, count($values), '?'));
Alternative 2 hat einen Fallstrick: count($values)==0. Das passiert, wenn keine Kategorie angehakt ist. Aber in dem Fall ist deine Query ohnehin so nicht brauchbar, das musst Du vorher abfangen. Ich denke, ohne Kategorien startest Du gar nicht erst die Suche...
String-Parsing durch double-quote Strings - magst Du das nicht?
// Dein Code
$stmt = $mysqli->prepare('SELECT ... WHERE kategorie IN (' .$s. ')');
// Mit String-Parsing:
$stmt = $mysqli->prepare("SELECT ... WHERE kategorie IN ($s)");
Referenzbildung geht einfacher:
// Dein Code
foreach ( $values as $k => $v ) {
${ 'varvar' . $k } = $v;
$params[] = &${ 'varvar' . $k };# provide references
}
// Alternative ohne dynamisch benannte Temp-Variablen
foreach ( $values as &$v ) { // Beachte das &
$params[] = &$v; // Nochmal Reference! Sonst klappt's nicht
}
Und auch bei dieser Lösung kannst Du mit einem Result-Objekt und fetch_all den bind_result und die Fetch-Schleife sparen.
Rolf
Tach!
Jetzt bleibt nur noch die Frage wie bekomme ich in meinem Arry
$kat = array(); $kat = $_GET["kat"];
bei $kat das letzte , weg?
Das Problem stellt sich nicht mehr, wenn du es etwas anders angehst, so wie es Rolf B schon vorgeschlagen hat. Du präparierst erst alle Werte mit passenden Anführungszeichen und Maskierung. Anschließend implodierst du das Array mit ',' als Trennzeichen. Die Funktion implode() fügt dabei nur die Kommas zwischen die Werte.
Bei zwei unbedingten Zuweisungen an dieselbe Variable ist die erste überflüssig, weil sie ja von der zweiten überschrieben wird.
substr($kat, 0, -2);
Da wird aber gemeckert
Warning: substr() expects parameter 1 to be string, array given in
Ja, weil das überflüssige Komma ja auch nur bei einem String vorkommen kann, nicht aber bei einem noch nicht flachgeklopften Array.
dedlfix.
Tach!
Nachtrag, meine Antwort ist teilweise gegenstandlos geworden, da du doch einen anderen anderen Weg genommen hast.
dedlfix.
Unter uns Rolf,
eine !SQL Lösung wäre auch mit PHP's array_intersect()
möglich.
MfG