A comanda. Accelerarea interogărilor bazei de date folosind PDO și iteratoare Opțiuni de proiectare a traducerii pentru fizic

Am probleme cu parametrii din clauza ORDER BY a SQL-ului meu. Nu emite niciun avertisment, dar nu emite nimic.

$comanda = "ColumnName"; $directie = "ASC"; $stmt = $db->prepare("SELECT câmpul din tabelul WHERE coloana = :my_param ORDER BY:order:direction"); $stmt->bindParam(":my_param", $est_live, PDO::PARAM_STR); $stmt->bindParam(":comanda", $comanda, PDO::PARAM_STR); $stmt->bindParam(":direcție", $direcție, PDO::PARAM_STR); $stmt->execute();

The:my_param funcționează, dar nu:order sau:direction . Este aceasta o evadare internă? Îl pot introduce direct în SQL? Ca aceasta:

$comanda = "ColumnName"; $directie = "ASC"; $stmt = $db->prepare("SELECT * din tabelul WHERE coloana = :my_param ORDER BY $order $directie");

Există o constantă PDO::PARAM_COLUMN_NAME sau un echivalent?

Mulțumită!

Întrebarea aici este că declarațiile pregătite mult iubite nu sunt un glonț de argint, hehe :)

Da, ați rămas blocat să-l lipiți direct în SQL, cu unele precauții, desigur. Fiecare operator/identificator trebuie să fie codificat în script-ul dvs., de exemplu:

$comenzi=matrice("nume","pret","cantitate"); $key=array_search($_GET["sortare"],$comenzi); $comanda=$comenzi[$cheie]; $query="SELECT * din tabelul WHERE is_live = :is_live ORDER BY $order"; - $comenzi=matrice("nume","pret","cantitate"); $key=array_search($_GET["sortare"],$comenzi); $comanda=$comenzi[$cheie]; $query="SELECT * din tabelul WHERE is_live = :is_live ORDER BY $order";

Același lucru pentru direcție.

Rețineți că bindParam nu scapă, deoarece nu este necesară scăparea. este obligatoriu.

Nu cred că poți:

  • Utilizați substituenți în ordinea
  • Legați numele coloanelor: puteți lega doar valori – sau variabile – și puteți introduce valoarea acestora într-o declarație pregătită.

Este posibil să folosiți instrucțiuni pregătite în clauza ORDER BY, din păcate trebuie să treceți ordinea coloanei cu numele și trebuie să setați PDO_PARAM_INT cu tipul.

În MySQL puteți obține ordinea coloanelor cu această interogare:

SELECT coloană_name, ordinal_position FROM information_schema.columns WHERE table_name = "table" și table_schema = "database"

$comanda = 2; $stmt = $db->prepare("SELECT câmpul din tabelul WHERE coloana = :param ORDER BY:order DESC"); $stmt->bindParam(":param", $is_live, PDO::PARAM_STR); $stmt->bindParam(":comanda", $comanda, PDO::PARAM_INT); $stmt->execute();

Nu cred că puteți obține ASC/DESC ca parte a unei declarații pregătite, dar puteți obține o coloană.

Ordonați după caz: ordine când „colFoo” apoi colFoo când „colBar” apoi colBar altfel colDefault final $direcție

Deoarece ASC/DESC sunt doar două valori posibile, puteți testa cu ușurință și alege între ele ca valori codificate.

Puteți utiliza și funcțiile ELT (FIELD(,),) pentru a face acest lucru, dar apoi ordonarea se va face întotdeauna ca șir, chiar dacă este o coloană numerică.

Din păcate, nu cred că ai putea face asta cu declarații pregătite. Acest lucru l-ar face necacheabil, deoarece diferite coloane ar putea avea valori care ar putea fi sortate folosind strategii speciale de sortare.

Creați o interogare folosind ecrane standard și executați-o direct.

Este posibil. Puteți utiliza un număr în locul unui nume de câmp în clauza „ordonare după”. Acesta este un număr care începe cu 1 și are ordinea numelor câmpurilor din interogare. Și puteți concatena șirul la ASC sau DESC. De exemplu, „Selectați col1, col2, col3 din comanda tab1 pe?” + StrDesc + „limită 10,5”. strDesc = "ASC" / "DESC".

Dacă nu mă înșel, Pascal are dreptate.
Singura legare posibilă în PDO este legarea de valori, așa cum ați făcut cu parametrul „:my_param”.
Cu toate acestea, nu există niciun rău în acest lucru:

$stmt = $db->prepare("SELECT camp din tabelul WHERE coloana = :my_param ORDER BY ".$order ." ".$direction); $stmt->bindParam(":my_param", $est_live, PDO::PARAM_STR); $stmt->execute();

Singurul lucru la care trebuie să acordați atenție este obținerea corectă a $comanda și $direcția, dar din moment ce le setați manual și nu le setați prin introducerea utilizatorului, cred că sunteți gata.

Creați o condiție dacă altfel.
Dacă (ascCondion) atunci legați valorile dar codul hard ORDER BY columnName ASC
Mai mult
Leagă valori, dar cod dur ORDER BY ColumnName DESC

Pagina de proiectare a pluginului woocommerce are o anumită structură și funcționalitate. Dar această structură nu este în întregime convenabilă. Vom finaliza pagina de înregistrare, împărțind-o în blocuri logice: Comanda, Livrare, Forma de plată, Informații despre client etc.

Checkout (structură de bază)

Șablon formular-checkout.php
nume formular="checkout"

woocommerce_checkout_billing (informații despre client)
woocommerce_checkout_shipping (informații de expediere)

h3 Comanda /h3
div id="order_review" Order-review /div

Șablon review-order.php (Comandă-revizuire)
masa
articole pentru cumpărare
total
expediere (cart-shipping.php, dependență ajax de informațiile introduse în woocommerce_checkout_billing, mai multe despre transport)
/masa

div id=”plată” Formular de plată /div (conectat cu cârlig)

Plasați un buton de comandă

Am pregătit o diagramă mai vizuală pentru care zonă de design este responsabilă pentru ce șablon Woocommerce

Blocarea „Selectarea unei metode de livrare”

Șablonul care este responsabil pentru afișarea blocului cu alegerea opțiunilor de livrare se află (din anumite motive) aici: cart/cart-shipping.php.

Inscripția Livrare, care este prezentă inițial acolo, este afișată cu această linie:

Echo wp_kses_post($nume_pachet);

Puteți adăuga antetul „Selectați o metodă de livrare” și greutatea totală a comenzii direct în blocul de livrare folosind cârligul

Funcția action_woocommerce_review_order_before_shipping() ( echo „Selectați metoda de livrare”; global $woocommerce; echo „Greutate totală: „; $total_weight = $woocommerce->cart->cart_contents_weight; $total_weight .= " ".get_option("woocommerce_weight_unit"); echo $greutate_totală; add_action("woocommerce_review_order_before_shipping", "action_woocommerce_review_order_before_shipping", 10, 0);

Finalizarea elementelor

Dacă nu folosim funcționalitatea pentru calcularea livrării și aplicarea cupoanelor, putem dezactiva actualizarea ajax. Dacă nu trebuie să dezactivați ajax, există o metodă de mai jos fără a o dezactiva.

// Dezactivează Ajax pe pagina de finalizare jQuery(document.body).on("update_checkout", function(e)( //e.preventDefault(); //e.stopPropagation(); e.stopImmediatePropagation(); // consola .log(e);

Mutați blocul Formulare de plată

Remove_action(„woocommerce_checkout_order_review”, „woocommerce_checkout_payment”, 20); add_action("woocommerce_after_order_notes", "woocommerce_checkout_payment", 20); sau conectați-vă la propriul cârlig

Dezactivarea calculelor de livrare

Dacă livrarea este destul de complexă și este imposibil să o înregistrăm automat (de exemplu: dacă nu putem calcula cu adevărat ce gazelă este necesară), atunci dezactivăm calculul livrării: pur și simplu lăsăm Pickup and Delivery (cu preț 0) în livrare metode. În același timp, eliminăm câmpurile legate de livrare din formularul de informații despre client și invers, eliminăm câmpurile legate de client din formularul de livrare. Și creăm un script când faceți clic pe elementul de livrare, care dezvăluie formularul de livrare.

Id-ul câmpului cu articolul Livrare

$(document).ready(function() ( if($("#shipping_method_0_flat_rate-6")). este(':verificat')) ( $('.shipping_address').show(); ) $('.shipping_method') ').click(function())( if($("#shipping_method_0_flat_rate-6")). este(':verificat')) ( $('.shipping_address').show(); $('.shipping_address') html('

informatii despre livrare

‘); ) else ( $(‘.shipping_address’).html(‘

‘); $('.shipping_address').hide(); ) )); ));

Această opțiune de implementare nu este o soluție completă, deoarece are o serie de dezavantaje și se bazează pe o abordare destul de primitivă

Relația dintre opțiunea de livrare și câmpuri

Metodă pentru 2 opțiuni de livrare (nu este potrivit pentru 3 sau mai multe)

Dacă avem opțiuni de livrare și ridicare, atunci ar fi bine să sincronizăm opțiunea de livrare și câmpurile oferite pentru completare. La ridicare este necesar ca câmpurile de livrare să fie ascunse, dar să apară la selectarea unei opțiuni de livrare.

Problema woocommerce este că formularul Detalii de livrare se extinde atunci când se face clic pe antetul de livrare la o altă adresă. (#ship-to-different-address) și împreună cu ascunderea câmpului, verificarea câmpurilor de livrare este dezactivată. Cu două opțiuni de livrare (Ridicare și Livrare), atunci când le comutați, puteți seta un eveniment (clic) pe id-ul de expediere la adresă diferită folosind jquery. În acest caz, este necesar să vă asigurați că unul dintre câmpuri este inițial activ, în funcție de nevoie.

$("#metoda_de_livrare_0_rata_plan-2").attr("verificat",true); $("input:radio").on("schimbare", function () ( $("#ship-to-different-address-checkbox").click(); ));

Pentru ca câmpurile de livrare să fie deschise inițial, trebuie să setați setarea de livrare în opțiunile woocommerce
Destinație de livrare > Implicit pentru adresa de livrare a clientului

În câmpul oraș, puteți face în mod implicit înlocuirea automată
$("#shipping_city")val("Rostov-pe-Don");

Metodă pentru 3 sau mai multe opțiuni de livrare

Initial facem livrarea (una dintre optiuni) si campurile de livrare sunt active. Următoarea magie jquery

$("input:radio").on("schimbare", funcția () ( if($("#shipping_method_0_local_pickup-2").is(":verificat")) ( if($("#ship-to-) caseta-de-verificare-adresă-diferită").is(":bifat")) ( $("#ship-to-different-address-checkbox").click(); ) else ( ) ) else ( if($("# ship-to-different-address-checkbox").is(":checked")) ( ) else ( $("#ship-to-different-address-checkbox").click(); ) ) ));

În acest caz, verificăm dacă câmpul Pickup este activ (#shipping_method_0_local_pickup-2) și, în funcție de aceasta, bifăm caseta de selectare ascunsă (I hide it) (Livrare la o altă adresă? #ship-to-different-address) .

Fără a dezactiva ajax

Ajax pe pagina de checkout este necesar într-un fel sau altul (pentru aceleași cupoane). Prin urmare, să schimbăm puțin (modificările au afectat prima linie, deoarece elementele DOM nu fuseseră încă create) la scriptul universal pentru dezactivarea câmpurilor de livrare. #shipping_method_0_local_pickup-3 — ID-ul câmpului de ridicare.

$("corp").on("schimbare", "input:radio", funcția(e) ( if($("#shipping_method_0_local_pickup-3").is(":verificat")) ( if($(" #ship-to-different-address-checkbox").is(":bifat")) ( $("#ship-to-different-address-checkbox").click(); ) else ( ) ) else (dacă ($("#ship-to-different-address-checkbox").is(":checked")) ( ) else ( $("#ship-to-different-address-checkbox").click(); ) ) ));

Și pentru orice eventualitate, includem alegerea inițială pentru orice livrare

$("#metoda_de_livrare_0_rata_plan-4").attr("verificat",true);

Memento: în setările de livrare, trebuie selectată Destinația de livrare - Implicit pentru adresa de livrare a clientului

Opțiuni de design pentru persoane fizice persoane si persoane juridice chipuri

Sarcina este de a face 2 opțiuni pentru plasarea unei comenzi pentru persoane fizice. persoane si persoane juridice chipuri. Crearea acestei funcționalități este descrisă în articol

Pe măsură ce cercetezi kilometri de cod, s-ar putea să te întrebi: „De ce totul este făcut așa cum este?” Personal, observ mai ales lucruri care pot și ar trebui îmbunătățite atunci când vine vorba de interogări grele de baze de date.

Dezvoltare fără cadru

Când se lucrează cu cadrul, interogările din baza de date sunt practic deja optimizate pentru dezvoltator și logica complexă este abstractizată, ceea ce îmbunătățește și optimizează regăsirea și utilizarea ulterioară a datelor. Dar se întâmplă că dezvoltatorii trebuie să codifice ceva fără a utiliza un cadru. În același timp, principalele caracteristici ale PHP nu sunt adesea folosite în cel mai optim mod.

$pdo = nou \PDO($config["db"]["dsn"], $config["db"]["nume utilizator"], $config["db"]["parola"]); $sql = "SELECT * FROM `gen_contact` ORDER BY `contact_modified` DESC"; $stmt = $pdo->prepare($sql); $stmt->execute(); $date = $stmt->fetchAll(\PDO::FETCH_OBJ); echo „Obținerea contactelor care s-au schimbat în ultimele 3 luni” . PHP_EOL; foreach ($date ca $rând) ( $dt = new \DateTime("2015-04-01 00:00:00"); if ($dt->format("Y-m-d") . "00:00:00"< $row->contact_modified) ( echo sprintf ("%s (%s)| modificat %s", $row->contact_name, $row->contact_email, $row->contact_modified) . PHP_EOL; ) )

Mai sus este un exemplu de cod care este cel mai frecvent utilizat pentru a prelua date. La prima vedere, acest cod pare frumos și curat, dar dacă aruncați o privire mai atentă, veți vedea câteva oportunități de îmbunătățire.

  • Codul nu este reutilizabil. Când trebuie să utilizați o funcționalitate similară, va trebui să duplicați codul existent.
  • Chiar dacă utilizați $stmt->fetchAll(\PDO::FETCH_OBJ); mai ai o problema pentru ca... Ieșirea va fi o matrice de obiecte. Cu un eșantion mare, aceasta va consuma multă memorie.
  • Filtrarea se face folosind o funcție. Aceasta înseamnă că, dacă sunt necesare alte condiții de filtrare, va trebui să modificați logica curentă, ceea ce nu va adăuga prea mult în ceea ce privește ușurința întreținerii și extinderea funcționalității.
Iteratori

Cele mai multe cadre moderne folosesc iteratoare pentru a prelua date deoarece sunt rapide și reutilizabile. De asemenea, vă permit să utilizați alți iteratoare pentru a filtra și modifica rezultatele returnate. Dar le poți folosi chiar și fără cadru, pentru că... Iteratorii fac parte din PHP din versiunea 5.0.0 Beta 2.

Deci, să ne imaginăm că continuați să utilizați PDO pentru a prelua date. Avem ca optiune:

  • Utilizați PDOStatement::fetchAll() pentru a prelua toate datele într-o singură trecere.
  • Utilizați PDOSTatement::fetch() pentru a prelua un rând pe iterație.

Chiar dacă prima variantă ți se pare foarte tentantă, prefer și recomand să folosești opțiunea numărul doi. Îmi permite să creez un singur iterator pentru preluarea datelor fără a fi constrâns de condițiile de interogare (făcându-l reutilizabil pentru orice extragere).