PHP Funktion mit unbekannten Werten
Sophie
- php
Hallo,
vielleicht könnt ihr mir weiterhelfen. Ich habe eine kleine PHP Funktion
function zeiterfassung($mysqli, $name=false, $projektnummer=false,
$datum_von=false, $datum_bis=false) {
$select = "SELECT id, code, projektnummer, name, datum, betreff, anzStunden, jahr, monat, tag
FROM zeiterfassung ";
if ($projektnummer) {
$stmt = $mysqli->prepare($select . " WHERE projektnummer =?" );
$stmt->bind_param("s", $projektnummer);
} else {
$stmt = $mysqli->prepare($select);
}
if ($name) {
$stmt = $mysqli->prepare($select . " WHERE name =?" );
$stmt->bind_param("s", $name);
} else {
$stmt = $mysqli->prepare($select);
}
$stmt->execute();
$stmt->bind_result($id, $code, $projektnummer, $name, $datum, $betreff, $anzStunden,
$jahr, $monat, $tag);
$stmt->store_result();
Ich möchte gerne nach allem suchen können. Also entweder nach Namen, Projektnummer oder dem Datum, oder auch mal nach zwei Kombinationen gleichzeig also z.B. Name = Sophie Projektnummer A0101
Ich habe gehört, dass bind_param() immer alle Werte benötigt, die rein kommen und man die Funktion call_user_func_array nehmen muss. Allerdings verstehe ich nicht, wie ich diese auf meine Funktion anwenden soll.
Der Aufruf meiner Funktion
$name = NULL;
$projektnummer = NULL;
$datum_von = NULL;
$datum_bis = NULL;
if(isset($_POST['abschicken'])){
if(!empty($_POST['name'])) { $name = $_POST['_name']; }
if(!empty($_POST['projektnummer'])) { $projektnummer = $_POST['projektnummer']; }
if(!empty($_POST['datum_von'])) { $datum_von = $_POST['datum_von']; }
if(!empty($_POST['datum_bis'])) { $datum_bis = $_POST['datum_bis']; }
}
$zeiterfassung_ausgabe = zeiterfassung($mysqli, $name, $projektnummer, $datum_von, $datum_bis);
Hello,
eine Idee wäre es, deine SQL-Abfrage in der API so aufzubereiten, dass sie neutrale Werte erhält, wenn kein Wunschwert übergeben wurde.
Neutraler Wert könnte z. B. NULL
sein. Das hängt aber vom jeweiligen Spaltentyp ab. GGf müsstest Du das auch in der SQL-Abfrage selber durch ein if
abfangen.
Liebe Grüße
Tom S.
Hey,
Nur eine kleine Änderung um etwas sauberer zu sein.
(1 Minute später) Und dabei fällt mir dann auch grad das auf was du erreichen möchtest, so wie ich glaube.
(noch 2 Minuten später) Wieso setzt du die Variablen Du brauchst dort die Variablen nicht auf False setzen oder tu das dierkt bei der initialisierung.$name
, $projektnummer
,... =false
, da kommt doch in der Funktion nur False an
Mit der geänderten Kontrollstruktur, ist es dann auch möglich, in einem Datumsbereich zu suchen. Könnte dann aber unübersichtlich werden.
function zeiterfassung($mysqli, $name=false, $projektnummer=false, $datum_von=false, $datum_bis=false) { $select = "SELECT id, code, projektnummer, name, datum, betreff, anzStunden, jahr, monat, tag FROM zeiterfassung "; if ($projektnummer != false && $name != false) { $stmt = $mysqli->prepare($select . " WHERE projektnummer =? AND name=?" ); $stmt->bind_param("ss", $projektnummer, $name); } elseif ($projektnummer != false) { $stmt = $mysqli->prepare($select . " WHERE projektnummer =?" ); $stmt->bind_param("s", $projektnummer); } elseif ($name != false) { $stmt = $mysqli->prepare($select . " WHERE name =?" ); $stmt->bind_param("s", $name); } else { $stmt = $mysqli->prepare($select); } $stmt->execute(); $stmt->bind_result($id, $code, $projektnummer, $name, $datum, $betreff, $anzStunden, $jahr, $monat, $tag); $stmt->store_result();
Gruß
Jo
Hall und guten Abend @j4nk3y
vielen vielen vielen lieben Dank für deine Hilfe. Du hast mir wirklich den Abend gerettet.
Also haben mich andere angelogen die meinten, es geht nur mit der PHP Funktion call_user_func_array?
Deine Änderungen funktionieren wunderbar. Jetzt habe ich noch eine Frage. Wenn ich nach dem Datum noch filtern möchte, dann muss ich diesen Blog kopieren und eben auf das Datum abändern?
elseif ($usz_name != false) {
$stmt = $mysqli->prepare($select . " WHERE usz_name =?" );
$stmt->bind_param("s", $usz_name);
}
Das gleiche gilt dann für den Blog, bis richtig? Wenn ich von bis filtern möchte, dann muss ich einen weiteren Blog einfügen, richtig?
Und jetzt treibe ich es noch ein Schritt weiter, wenn ich sage, ich möchte nach folgenden filtern:
Oder
Oder
Oder
Das heißt also, ich muss für jede Option ein Blog einbauen, richtig?
Hallo Sophie,
Also haben mich andere angelogen die meinten, es geht nur mit der PHP Funktion call_user_func_array?
Lügen bedeutet wissentlich die Unwahrheit sagen. Wenn jemand aus Unwissenheit etwas behauptet, das sich als unwahr erweist, lügt er nicht. Möglich auch, dass sein Kenntnisstand einfach veraltet ist. Etwa, wenn jemand sagt, dass es in unserem Sonnensystem 9 Planeten gibt.
Bis demnächst
Matthias
Hey,
vielen vielen vielen lieben Dank für deine Hilfe. Du hast mir wirklich den Abend gerettet.
Gerne :)
Also haben mich andere angelogen die meinten, es geht nur mit der PHP Funktion call_user_func_array?
Keine Ahnung, ich hab die Funktion noch nie gebraucht/gesehen. Dementsprechend weiß ich nicht was diese macht oder wofür man diese brauchen könnte.
Deine Änderungen funktionieren wunderbar. Jetzt habe ich noch eine Frage. Wenn ich nach dem Datum noch filtern möchte, dann muss ich diesen Blog kopieren und eben auf das Datum abändern?
elseif ($usz_name != false) { $stmt = $mysqli->prepare($select . " WHERE usz_name =?" ); $stmt->bind_param("s", $usz_name); }
Das gleiche gilt dann für den Blog, bis richtig? Wenn ich von bis filtern möchte, dann muss ich einen weiteren Blog einfügen, richtig?
Und jetzt treibe ich es noch ein Schritt weiter, wenn ich sage, ich möchte nach folgenden filtern:
- Name
- Von
- Bis
Oder
- projektnummer
- Bis
Oder
- projektnummer
- von
- bis
Oder
- Name
- bis
Das heißt also, ich muss für jede Option ein Blog einbauen, richtig?
Richtig aber wie du merkst wird das recht komplex. Wie ich es auch gerade drehe und wende, finde ich keine elegante Lösung. Die Schwierigkeit liegt zum einen darin, dass du 4 Variablen hast, welche dann (wenn ich mich grad nicht irre) in 4! = 16 Möglichkeiten endet und darin, dass das Statement ein AND
in der Bedingung braucht wenn es denn mehrere gibt. Sprich bei jeder Möglichkeit, außer bei keiner false
und alle false
, musst du prüfen ob davor schon eine wahr war um das entsprechende AND
zu setzen.
Eine Möglichkeit gäbe es vielleicht um starke Kopfschmerzen zu vermeiden.
Du baust dir das Statement so wie du es brauchst und wenn die Variable false
ist lässt du dir alles ausgeben mit Where xyz Like=%
. Das kann man dann noch in eine abfrage bauen mit ((xyz == false) ? "Where xyz Like=%" : "Where xyz = ".$xyz )
.
FYI ((Abfrage) ? Ergebnis true : Ergebnis false)
Und wo ich es gerad fertig geschrieben hab kommt mir wieder das AND
in die Quere.
Ich lasse mir das heute Nacht nochmal durch den Kopf gehen, vielleicht komme ich ja auf eine schicke Lösung.
Gruß
Jo
Hallo j4nk3y,
Die Schwierigkeit liegt zum einen darin, dass du 4 Variablen hast, welche dann (wenn ich mich grad nicht irre) in 4! = 16 Möglichkeiten endet
Hier irrst du teilweise.
4! = 1 × 2 × 3 × 4 = 24.
Da es für 4 Variablen aber jeweils 2 Möglichkeiten gibt, sind es insgesamt
2 × 2 × 2 × 2 = 2⁴ = 16 Möglichkeiten.
Bis demnächst
Matthias
Hey,
Die Schwierigkeit liegt zum einen darin, dass du 4 Variablen hast, welche dann (wenn ich mich grad nicht irre) in 4! = 16 Möglichkeiten endet
Hier irrst du teilweise.
4! = 1 × 2 × 3 × 4 = 24.
Da es für 4 Variablen aber jeweils 2 Möglichkeiten gibt, sind es insgesamt
2 × 2 × 2 × 2 = 2⁴ = 16 Möglichkeiten.
Danke für die Korrektur, bin schon etwas müde und hab morgen eine Klausur und bin nicht ganz bei der Sache.
Gruß
Jo
Hallo j4nk3y,
bin schon etwas müde und hab morgen eine Klausur
Viel Erfolg!
Bis demnächst
Matthias
Tach!
(noch 2 Minuten später)
Wieso setzt du die VariablenDu brauchst dort die Variablen nicht auf False setzen oder tu das dierkt bei der initialisierung.$name
,$projektnummer
,...=false
, da kommt doch in der Funktion nur False an
Das sind nur Default-Werte, die genommen werden, wenn man weniger Wert an die Funktion übergibt, als sie eigentlich Parameter haben möchte. Wenn Werte übergeben werden, werden diese statt dem false in der Variable landen.
Mit der geänderten Kontrollstruktur, ist es dann auch möglich, in einem Datumsbereich zu suchen. Könnte dann aber unübersichtlich werden.
Eben, und deshalb war die Empfehlung mit dem call_user_func_array() schon nicht schlecht. Damit muss man nicht für jeden neuen Parameter die Struktur erweitern. Mit den steigenden Kombinationsmöglichkeiten wachsen dann auch die Verzweigungen, und das nicht linear.
Allerdings ist auch eine Lösung damit nicht trivial. mysqli_stmt::bind_param() möchte Variablen per Referenz übergeben haben. Und das passt nicht so ganz zur Arbeitsweise von call_user_func_array(). Einfacher kommt man in einem solchen Fall mit PDO. Dessen PDOStatement::bindParam() lässt sich einzeln und damit auch problemlos in einer Schleife aufrufen. Alternativ kann man auch dem PDOStatement::execute() einfach ein Array übergeben.
dedlfix.
Hey,
(noch 2 Minuten später)
Wieso setzt du die VariablenDu brauchst dort die Variablen nicht auf False setzen oder tu das dierkt bei der initialisierung.$name
,$projektnummer
,...=false
, da kommt doch in der Funktion nur False anDas sind nur Default-Werte, die genommen werden, wenn man weniger Wert an die Funktion übergibt, als sie eigentlich Parameter haben möchte. Wenn Werte übergeben werden, werden diese statt dem false in der Variable landen.
Das ist mir bewusst aber sie werden ja in jedem Fall mit dem Wert NULL
an die Funktion gegeben außer, sie werden durch den in $POST[]
stehenden Wert überschrieben.
Gruß
Jo
Ich würde die Filter-Logik von PHP komplett nach MySQL verfrachten.
Du kannst in der WHERE-Klausel ausdrücken, dass du nur nach einem Namen filtern willst, wenn auch wirklich ein Name angebgen wurde. Das sähe dann so aus WHERE (? IS NULL OR name = ?)
. Bei bind_param
müsstest du dann beide ?
durch $name
ersetzen lassen. Wenn $name === null
ist, dann wird die Klausel zu WHERE (NULL IS NULL OR name = NULL)
, das heißt die Bedingung ist immer wahr und es wird kein Datensatz gefiltert. Wenn $name === 'Biff'
ist, dann wird die Klausel zu WHERE ('Biff' IS NULL OR name = 'Biff')
und der Filter ist aktiv. Der Filter lässt sich dann auch einfach kombinieren:
function zeiterfassung($mysqli, $name = null, $projektnummer = null, $datum_von = null, $datum_bis = null) {
$select = "
SELECT id, code, projektnummer, name, datum, betreff, anzStunden, jahr, monat, tag
FROM zeiterfassung
WHERE (? IS NULL OR name = ?)
AND (? IS NULL OR projektnummer = ?)
AND (? IS NULL OR datum_von >= ?)
AND (? IS NULL OR datum_bis <= ?)";
$query = $mysqli->prepare($select);
$query->bind_param(
'ssssiiii',
$name, $name,
$projektnummer, $projektnummer,
$datum_von, $datum_von,
$datum_bis, $datum_bis
);
// …
}
Hello,
danke für dieses ausführliche Beispiel. (+1)
Kommt gleich in meine Sammlung.
Ich würde die Abfragewerte allerdings als Array übergeben. Damit lassen sich dann die Daten bequemer (als "Record") aus dem allgemeinen Programmfluss entnehmen.
Liebe Grüße
Tom S.
Tach!
Ich würde die Abfragewerte allerdings als Array übergeben. Damit lassen sich dann die Daten bequemer (als "Record") aus dem allgemeinen Programmfluss entnehmen.
Dann musst du dir aber was ausdenken, wie du das Array an bind_param() übergibst, und das auch noch funktionierend, weil Referenzen beachtet werden müssen. Entweder war das die ziemlich gravierende Herausforderung oder beim Ergebnis-Binden. Ich hab das Wissen darüber schon wieder verdrängt. Lieber PDO nehmen, das ist deutlich verwenderfreundlicher bei Prepared Statements.
dedlfix.