Checkbox update meerdere tabellen MySQL, Ajax en PHP

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Senior DevOps-ontwikkelaar eIDAS

Functie­omschrijving Burgers en bedrijven veilig en betrouwbaar digitaal toegang geven tot diensten en producten van het ministerie van Economische Zaken en Klimaat. Als senior DevOps-ontwikkelaar bouw je daar letterlijk aan mee. En dat doe je bij DICTU: een van de grootste en meest vooruitstrevende ICT-dienstverleners van de Rijksoverheid. Jij werkt mee aan de doorontwikkeling van eIDAS, dat staat voor Electronic IDentification Authentication and trust Services. Deze koppeling maakt de grensoverschrijdende authenticatie op overheidswebsites binnen de Europese Unie mogelijk. Het ministerie van Economische Zaken en Klimaat heeft één moderne toegangspoort voor zijn diensten en inspecties. Enkele daarvan zijn dankzij eIDAS inmiddels

Bekijk vacature »

Stefan Janssen

Stefan Janssen

21/01/2020 13:24:18
Quote Anchor link
Goede middag,

Waar ik mee zit is het volgende:

Gebruikers kunnen data invoeren, dit d.m.v. tekst en checkboxes.
Deze dat word opgeslagen met een AJAX call naar het PHP script die via een MySQL query de data opslaat.
Deze data word in 2 tabellen opgeslagen. De tekst data in tabel products en de checkboxes in de koppeltabel productrel.
De koppeltabel gebruik ik voor de categorieën te koppelen met de tabel cats.

Onderstaand een simpele uitleg van de structuur.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Producten
+---+------------+
|ID   | NAAM          |
+---+------------+
|  1   |Kookboek     |
+---+------------+
|  2  |Lotion           |
+---+------------+
|  3  |Rijles theorie|
+---+------------+

Cats
+---+----------+
|ID   | NAAM      |
+---+----------+
|  1   |Speelgoed|
+---+----------+
|  2  |Body          |
+---+----------+
|  3  |Boeken      |
+---+----------+
|  4  |Verzorging|
+---+----------+

productrel
+---+----+
|PID | CID|
+---+----+
|  1   |  3   |
+---+----+
|  2  |   2   |
+---+----+
|  3  |   1   |
+---+----+
|  2  |   4   |
+---+----+


Waar loop ik vast?

Als er een wijziging moet plaatst vind, moet de data worden ge-update worden.
Hiervoor maak ik gebruik van JSON zodat JavaScript de inputs vult.

Hoe kan ik dit het beste doen voor de checkboxes?
Zelf dacht ik aan een array terug te sturen en JavaScript de checkboxes als checked te markeren.

Daarnaast moet de koppeltabel ook ge-update worden.
Word er een checkbox unchecked dan moet deze ook van de koppeltabel verwijderd worden maar ook als in de wijziging van het product er een ander checkbox word aangevinkt dan moet deze in de koppeltabel juist ingevoerd worden.

Kan iemand mij hierbij helpen?
 
PHP hulp

PHP hulp

27/09/2020 06:30:28
 
Thomas van den Heuvel

Thomas van den Heuvel

21/01/2020 17:49:32
Quote Anchor link
Waarom AJAX? Dit klinkt als een administratief systeem. Als je van $_POST gebruik kunt maken zonder AJAX/JSON in een aparte verwerkstap dat lijkt mij een stuk minder complex? Is AJAX/JSON enkel bedoeld om het er wat aantrekkelijker uit te laten zien? Dan is dit uitsluitend cosmetische fluf :p. Als je nog aan het ontwikkelen bent dan vormt dit een extra barrière die dingen (op dit moment) onnodig complex maakt. Het is namelijk een stuk lastiger te debuggen dan, zeg, het dumpen van $_POST.

Quote:
Daarnaast moet de koppeltabel ook ge-update worden.
Word er een checkbox unchecked dan moet deze ook van de koppeltabel verwijderd worden maar ook als in de wijziging van het product er een ander checkbox word aangevinkt dan moet deze in de koppeltabel juist ingevoerd worden.

De makkelijkste manier is de geassocieerde records weggooien en opnieuw vullen. Daarbij is het ook zaak dat dit in één handeling gebeurt zodat je administratie blijft kloppen. Ik hoop dat je voor InnoDB-tabellen hebt gekozen zodat je database-transacties kunt gebruiken, want die worden op het moment dat je dit soort dingen wilt gaan doen noodzakelijk.

Stel namelijk dat je geen transacties gebruikt, en er halverwege zo'n bijwerk-actie iets misgaat. Dan is er mogelijk sprake van half verbroken/half gemaakte relaties tussen records en klopt je administratie niet meer. Een database-transactie garandeert dat zo'n batch van wijzigingen in zijn geheel of in zijn geheel niet wordt uitgevoerd.

Als je een administratief systeem hebt met dito database dan is InnoDB eigenlijk de gedoodverfde keuze. Daarbij is het ook zaak dat je grote zorg besteed aan het database-ontwerp.
 
Stefan Janssen

Stefan Janssen

21/01/2020 21:46:07
Quote Anchor link
Hallo Thomas,


Bedankt voor je reactie!
Het betreft inderdaad een administratief systeem, ik maak gebruik van AJAX omdat de databaes extern geladen word.
Er word inderdaad gebruik gemaakt van de InnoDB engine.

Dus je zegt eigenlijk in een handeling de rijen verwijderen via bijvoorbeeld het ID en dan een nieuwe record ervan maken?
 
Thomas van den Heuvel

Thomas van den Heuvel

22/01/2020 01:00:22
Quote Anchor link
Yep, delete de categorieën waartoe het product behoort, en koppel deze opnieuw aan het product bij een bijwerk-actie.
In de koppeltabel uiteraard :p.

En als je categorie-relatie een ON DELETE CASCADE heeft in deze koppeltabel worden de records meteen opgeschoond als er een categorie wordt verwijderd uit de categorie-tabel. Foreign key relaties kunnen het op orde houden van de database verder vergemakkelijken.

Dus concreet ongeveer het volgende (aangenomen dat je de data van product X aan het wijzigen bent):
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
start transactie
    werk data van product X bij
    verwijder records van product X uit koppeltabel(len)
    vul koppeltabel(len) opnieuw met relaties met product X
commit transactie
Gewijzigd op 22/01/2020 01:04:05 door Thomas van den Heuvel
 
Stefan Janssen

Stefan Janssen

23/01/2020 22:29:23
Quote Anchor link
Hi Thomas,

Bedoel je zoiets
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$mysqli
= new mysqli("$hostdb", "$userdb", "passworddb", "db");

if ($mysqli->connect_errno) {
    printf("Connect failed: %s\n", $mysqli->connect_error);
    exit();
}


$mysqli->begin_transaction();

$mysqli->query("UPDATE products SET productname='$productname' WHERE id=$id");
$mysqli->query("DELETE FROM relation WHERE PID=$id");
foreach($categorieids as $categoryid){
    $mysqli->query("INSERT INTO relation (PID, CID) VALUES ('$productid', '$categoryid')");
}

$mysqli->commit();
$mysqli->close();
?>
 
Thomas van den Heuvel

Thomas van den Heuvel

23/01/2020 23:37:06
Quote Anchor link
Ziet er goed uit.

Enige kanttekeningen:
Vergeet niet een character encoding te selecteren na het maken van een connectie (met set_charset()) en escape alle data in je queries m.b.v. quotes + real_escape_string(). Dit om (later) problemen met input en output te voorkomen (invoer die quotes of non-ASCII karakters bevat).

Het loont misschien de moeite om een (kleine) wrapper te schrijven rondom de mysqli-class zodat je hier wat sneller/makkelijker mee kunt werken. Deze eenmalige investering ver*dient zich snel terug.
Gewijzigd op 24/01/2020 19:37:37 door Thomas van den Heuvel
 
Stefan Janssen

Stefan Janssen

24/01/2020 12:50:57
Quote Anchor link
Hi Thomas,


Bedoel je dat ik classes maak zoals onderstaande gevonden op het internet
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
    public function update($args)
    {

        $this->type = 'update';
        $this->setTable($args['table']);
        $query = $this->genQuery($args);
        $stmt = $this->mySqli->prepare($query);
        if ($this->mySqli->errno) {
            die('Unable to insert data:<br /> '.$this->mySqli->errno .' : '. $this->mySqli->error);
        }

        $this->bindPar($args);
        call_user_func_array(array($stmt, 'bind_param'), $this->returnRef($this->bind_arr));
        if (!$stmt->execute()) {
            die('Error : ('. $this->mySqli->errno .') '. $this->mySqli->error);
        }

        $stmt->close();
        $this->reset();
    }

?>


En vervolgens is deze overal aan te roepen met
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$args
= [
    'table' => 't1',
    'data' => [
        'f1' => 'test',
    ],

    'where' => [
        'id' => 10,
    ],

    'and' => [
        'f2' => 'foo',
    ]
    ];


$db->update($args);
?>
Gewijzigd op 24/01/2020 12:51:39 door Stefan Janssen
 
- Ariën -
Beheerder

- Ariën -

24/01/2020 15:22:19
Quote Anchor link
Thomas is blijkbaar fan van wrappers. :-P
Maar op zo een moment ben ik persoonlijk van mening dat je een afweging tussen kosten, tijd en baten moet maken of het zinvol is. De MySQLi-functies zullen voorlopig niet worden aangepast, en als het zo zou zijn, dan is een algehele check-up van je code vast ook zeker nodig omdat er in een major versie vast nog meer dingen aangepast zullen worden. Doe gewoon wat jij het fijnst vindt werken. :-)

Voor een grote applicatie zie ik het nut er wel van in, hoewel je dan eigenlijk al aan een framework zoals Symfony of Laravel denkt die dit al aan boord heeft. Maar voor een kleine site vind ik het tijdsverspilling, tenzij je het leuk vindt ;-)

Wel kan je met de OO-variant je de standaard MySQLi-class uitbouwen. Zo kan je bijvoorbeeld je query functie opnieuw opbouwen, maar dan met 'exceptions' erin, of een teller bijhouden die je queries telt.
Gewijzigd op 24/01/2020 17:01:47 door - Ariën -
 
Thomas van den Heuvel

Thomas van den Heuvel

24/01/2020 19:51:37
Quote Anchor link
@Stefan wat jij beschrijft is een volledige abstractielaag, zover hoef je nou ook weer niet (direct) te gaan :).

Quote:
De MySQLi-functies zullen voorlopig niet worden aangepast, en als het zo zou zijn, dan is een algehele check-up van je code vast ook zeker nodig omdat er in een major versie vast nog meer dingen aangepast zullen worden. Doe gewoon wat jij het fijnst vindt werken. :-)

...

Wel kan je met de OO-variant je de standaard MySQLi-class uitbouwen. Zo kan je bijvoorbeeld je query functie opnieuw opbouwen, maar dan met 'exceptions' erin, of een teller bijhouden die je queries telt.

Uh, spreek je hier jezelf niet een beetje tegen? En dat is toch een wrapper die je dan aan het schrijven bent?

Natuurlijk moet de wrapperfunctionaliteit je werk uit handen nemen, liefst zodat je met minder code hetzelfde/meer kunt doen.

Maar om terug te komen op het eerste fragment van bovenstaande quote: daar beschrijf je precies waarom een wrapper handig kan zijn: het ontkoppelt je code van een "hard coded" implementatie. Stel dat je overal real_escape_string() gebruikt, maar dat dat om een of andere reden (inhoudelijk) verandert (bijvoorbeeld dat je deze met extra of andere parameters moet aanroepen omdat er een default is veranderd). Dan zul je alle instanties van die aanroep overal in je code moeten opzoeken en moeten aanpassen (en daarmee propageer je in wezen het probleem van hard coding).

Had je daarintegen een (wrapper)methode gebruikt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
class MyDB {
    protected $db; // connection object

    // ...


    public function escape($in) {
        return $this->db->real_escape_string($in);
    }
}

?>

Dan hoe je enkel de desbetreffende regel code aan te passen en werkt vervolgens alle code die escape() gebruikt op de nieuwe manier.

Door deze ontkoppeling wordt het ook een stuk makkelijker om ondertussen te knutselen aan je wrapper-class, zonder dingen te breken in bestaande code, zolang je backwards compatible werkt, uiteraard.

En zoals @Ariën aangeeft kun je deze wrapper ook uitbouwen met extra functionaliteit zoals het (tijdelijk) loggen van queries, het tellen ervan, bijhouden of er al een transactie loopt et cetera.

EDIT: dus enkel al vanuit oogpunt van het verminderen van hard coding is er iets voor te zeggen om niet rechtstreeks de mysqli-functionaliteit te gebruiken.
Gewijzigd op 24/01/2020 19:53:49 door Thomas van den Heuvel
 
- Ariën -
Beheerder

- Ariën -

24/01/2020 20:00:32
Quote Anchor link
Tot hoever ga je met het maken van wrappers? Als je toch een wrapper voor MySQLi wilt maken kan je net zo goed ook een wrapper maken voor de string-functies van PHP, of de rekenkundige functies of misschien nog wel de uploadfuncties of de cryptografische functies.

Op sich maakt een wrapper het wel makkelijker, maar het blijft in mijn ogen een kosten-baten analyze.
En tja, alles aanpassen kan prima met een fatsoenlijke editor. 'Replace and edit' en eventueel met een tussentijdse check. Als je toch naar een nieuwe PHP-versie gaat waar een functie wordt aangepast kan dat zeker geen kwaad. Hoe vaak verandert een MySQLi-functie opeens volgens jouw?

Ik zie het nut er zelf niet echt van in. Behalve in het uitbouwen, maar dat zie ik niet als een globale wrapper.

Voor wie het leuk vindt, ga je gang... ;-)
Gewijzigd op 24/01/2020 20:12:07 door - Ariën -
 
Thomas van den Heuvel

Thomas van den Heuvel

24/01/2020 23:30:45
Quote Anchor link
Mja met bovenstaande redenatie hoef je nooit iets aan te passen.

string functies, rekenkundige functies en uploadfuncties zijn appels, peren en ander fruit wat je met elkaar vergelijkt. Als je functionaliteit kunt groeperen in een of een aantal klasses, zoals uploadfunctionaliteit, dan loont dat de moeite. Je koppelt daarmee de functionele acties los van de technische implementatie, of liever gezegd, je refereert hier op een indirect manier aan. Dit is ook een stukje "defensief programmeren".

En voor de rest, ooit gehoord van helper classes? Daarin hercombineer je standaard functies voor een specifiek gebruik die je vaker toepast. Dat zijn in feite ook "wrappers".

Binnen een uur kun je een mysql wrapper in elkaar draaien die je in de toekomst werk uit handen neemt, dus probeer het eens uit zou ik zeggen. Of kijk eens in het rond voor inspiratie, en gebruik de delen die jou nuttig lijken.

Quote:
Ik zie het nut er zelf niet echt van in.

Wat niet is kan mogelijk nog komen.

Geen idee wat je bedoelt met globale wrapper.
 
- Ariën -
Beheerder

- Ariën -

24/01/2020 23:45:38
Quote Anchor link
Ik zal kijken of het nut heeft. Voor zover is het wel handig om alias-functies te maken.
Maar om een uur te frotten aan iets wat de meeste gangbare functies wrapt, en waar je later hoogstwaarschijnlijk niets mee doet.
Het maakt mij in ieder geval niet warm.

Helperclasses ken ik wel, maar die zitten al in diverse frameworks die al kant en klare functies hebben. Dan hoef je ook geen wrapper meer te bouwen.
That's my opinion. ;-)

Verder is dit ook niet bepaald de scope van dit topic.
Gewijzigd op 24/01/2020 23:57:48 door - Ariën -
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.