Door
Donald Boers
op 23-07-2016 18:00
gewijzigd op 23-07-2016 18:04
2.674 views
Voor een facturatie systeem heb ik een pagina waar ik naar facturen wil kunnen zoeken. Dit zou moeten kunnen via een tekst veld, door op het ordernummer te zoeken (een specifieke factuur) of op de naam van een klant (kunnen meerdere facturen zijn). Ik dacht dit op de volgende manier te kunnen verwezenlijken:
Model
function klant_facturen_zoeken($search)
{
sql = "SELECT O.order_id
, O.order_datum
, K.naam
FROM offline_orders O
JOIN klant_gegevens K ON O.klant_id = K.klant_id
WHERE (O.order_id LIKE :search OR K.naam LIKE :search2)";
$stmt = $this->pdo->prepare($sql);
$stmt->execute(array(':search' => '%'.$search.'%', ':search2' => '%'.$search.'%'));
return $stmt->fetchAll();
}
waarbij de variabele $search het tekstveld in het formulier is.
Dit levert geen resultaten op. Terwijl wanneer de zelfde query in phpMyAdmin uitvoer met vaste waardes zoals:
SELECT O.order_id, O.order_datum , K.naam FROM offline_orders O JOIN klant_gegevens K ON O.klant_id = K.klant_id WHERE (O.order_id LIKE '%000001%' OR K.naam LIKE '');
of
SELECT O.order_id, O.order_datum , K.naam FROM offline_orders O JOIN klant_gegevens K ON O.klant_id = K.klant_id WHERE (O.order_id LIKE '' OR K.naam LIKE '%Donald Boers%');
krijg ik wel de juiste resultaten. Wat is er fout in mijn aanpak waardoor ik geen resultaten krijg.
Op regel 3
sql = "SELECT O.order_id
moet zijn
$sql = "SELECT O.order_id
Staat je foutmelding wel aan?
Sorry. Dat was een typo in het bericht. In de query zelf staat het namelijk wel goed. Dus de vraagt blijft bestaan wat ik fout doe of over het hoofd zie.
Ja zeker wel. Ik heb het zowel geprobeerd met alleen het order_id:
WHERE O.order_id LIKE :search
$stmt = $this->pdo->prepare($sql);
$stmt->execute(array(':search' => '%'.$search.'%'));
en hetzelfde met naam. En toen kreeg ik wel resultaten wanneer ik iets in tikte in het zoekveld. Vanaf het moment dat ik ze beidde gebruikte krijg ik geen resultaten meer
WHERE (O.order_id LIKE :search OR K.naam LIKE :search2)
Het ordernummer is een integer en de klantnaam een string.
Volgens die logica kun je de OR in de WHERE-clausule uitsplitsen.
<?php
public function klant_facturen_zoeken($search)
{
$sql = '
SELECT
O.order_id,
O.order_datum,
K.naam
FROM offline_orders O
JOIN klant_gegevens K ON O.klant_id = K.klant_id
';
// Zoek numeriek op ordernummer of alfanumeriek op klantnaam
if (is_numeric($search)) {
$sql .= 'WHERE O.order_id LIKE ?';
} else {
$sql .= 'WHERE K.naam LIKE ?';
}
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(1, "%$search%", \PDO::PARAM_STR);
$stmt->execute();
return $stmt->fetchAll();
}
?>
Hallo Ward. Hartelijk bedankt voor je reactie en oplossing. Ik ga dat zeer zeker proberen. Echter net voor jij reageerde heb ik een aantal wijzigingen aangebracht. Zo heb ik de naam van het zoekveld in het formulier veranderd van search in zoekTerm en in de Model heb ik de Param veranderd van $search in $term
function klant_facturen_zoeken($term)
{
$sql = "SELECT O.order_id
, O.order_datum
, K.naam
FROM offline_orders O
JOIN klant_gegevens K ON O.klant_id = K.klant_id
WHERE (order_id LIKE :term OR naam LIKE :term2)";
$stmt = $this->pdo->prepare($sql);
$stmt->execute(array(':term' => $term.'%', ':term2' => $term.'%'));
return $stmt->fetchAll();
}
Vervolgens heb ik de variabele term in de Controller gebruikt
En geloof het of niet het werkt. Ik probeer te achterhalen waar dit door komt? Voor zover ik weet is het woord search geen gereserveerd woord in mySql of ik moet me vergissen. Wellicht kun jij een verklaring verzinnen.
Maar nogmaals bedankt voor je reactie en tip over het uitsplitsen in de WHERE clause
Het probleem is een beetje dat je meerdere dingen tegelijkertijd hebt veranderd. Daarom is het moeilijk om precies aan te geven wat precies de oorzaak is. Zo:
- heb je de tabelaliassen O en K weggelaten in je WHERE-conditie
- zijn je LIKE criteria veranderd (nu enkel aan het einde een %)
- filter je je invoer op een andere manier
Echter, geen van deze wijzigingen, noch het veranderen van namen van formulierelementen of GET variabelen zouden volgens mij echt (veel) uit moeten maken. De enige manier om er achter te komen waarom de ene opzet wel werkt en de andere niet is door de query te loggen en te kijken wat MySQL hier uiteindelijk van maakt (oftewel, begin je zoektocht bij het einde: je query levert geen resultaat op waar je resultaat verwacht --> inspecteer de query). Ook wat @SanThe zegt: zorg dat (PHP) fouten oppikt (via error_reporting) en weergeeft (via display_errors).
Voor zover ik weet is het woord search geen gereserveerd woord in mySql of ik moet me vergissen.
Ik denk dat dat niet uitmaakt, dit zijn slechts placeholder-namen.
Wat wel van groot belang kan zijn is het volgende: afhankelijk van hoe jij een verbinding maakt met je database via PDO kan dit consequenties hebben over HOE fouten WAAR gemeld worden door PDO.
Allereerst: gebruik je PDO::ATTR_EMULATE_PREPARES? Dit bepaalt of PDO gebruik maakt van gesimuleerde prepares (ingeval deze instelling de waarde true heeft). Dit houdt in dat PDO het querysjabloon nooit vantevoren naar de database stuurt (wat wel gebeurt ingeval deze instelling de waarde false heeft, want de MySQL database heeft zelf ook een "native" prepared statements voorziening). Dus foutmeldingen over de syntax van de query komen dan niet tot uiting tijdens het preparen, maar pas tijdens de uitvoer. Default staat het emuleren van prepared statements aan. Heb je deze instelling niet expliciet geconfigureerd werkt het ook op die wijze.
En dat brengt ons bij het tweede dingetje: hoe handel jij fouten af via PDO? Oftewel wat voor waarde heeft PDO::ATTR_ERRMODE? De default waarde is PDO::ERRMODE_SILENT. Dit houdt in dat PDO normaal geen directe / visuele ruchtbaarheid geeft aan opgetreden fouten. Mocht je deze instelling niet expliciet geconfigureerd hebben is dat het default gedrag: er zal geen haan naar foutmeldingen kraaien.
Realiseer je je goed dat PDO niet op voorhand geschreven is voor een specifieke database en als gevolg hiervan niet op voorhand (optimaal) is geconfigureerd voor interactie met eerdergenoemde database. Naar mijn mening is het gewoon het beste om alle (al dan niet database-specifieke instellingen van de database-specifieke driver) instellingen expliciet in te stellen. Of gewoon MySQLi te gebruiken als je toch alleen van MySQL gebruik maakt :p.
Het venijn van PDO zit hem in de staart: PDO dwingt je om je te verdiepen in de werking van de database-specifieke driver die vervolgens met zorg geconfigureerd en behandeld moet worden. Als je hier geen weet van hebt dan zul je vaker voor dit soort puzzels komen te staan die vaak (?) naar configuratie herleidbaar zijn. En ja, debuggen van queries (de queries die de database concreet uitvoert) kan volgens mij alleen via de log.
EDIT: concreet: stel de instelling general_log in op ON en vul het pad naar de logfile in in general_log_file. Houd er wel rekening mee dat dit bestand vrij snel groeit dus gebruik dit uitsluitend voor (korte) debug sessies (en zet deze functionaliteit na afloop weer uit).