De globale configuratietabel van PrestaShop maakt het voor de uninstall-routine van een module eenvoudig om instellingen te wissen die toebehoren aan volledig ongerelateerde extensies. Eén enkele aanroep van Configuration::deleteByName('width') kan de aangepaste breedte-waarde van een andere shop wissen, waardoor de handelaar in verwarring raakt en de schuldige module onschuldig lijkt.

Waarom de gedeelde configuratietabel belangrijk is

PrestaShop slaat de instellingen van elke module op in één tabel die alleen een sleutel (key) en een waarde (value) bevat. De tabel heeft geen kolom die bijhoudt welke module een rij heeft aangemaakt, en er wordt geen naamgevingsconventie afgedwongen. Hierdoor zullen twee modules die toevallig dezelfde sleutel gebruiken — bijvoorbeeld "width" of "API_DATE_FROM" — dezelfde database-rij lezen en beschrijven. De laatste schrijfactie wint, en elke latere verwijdering verwijdert de rij voor beide partijen.

Wanneer uninstall-code verandert in een tool voor het wissen van gegevens

Een typische uninstall-methode ziet er als volgt uit:

public function uninstall()
{
    return Configuration::deleteByName('width');
}

De bedoeling is om de eigen configuratie van de module op te schonen, maar omdat de sleutel niet is voorzien van een namespace, verwijdert de instructie elke rij met de naam "width". Er wordt geen waarschuwing gelogd, er wordt geen uitzondering (exception) gegenereerd; de rij verdwijnt gewoon. De andere module van de handelaar verliest stilletjes zijn instelling en kan vreemd gedrag gaan vertonen.

Het probleem wordt extra verleidelijk tijdens een versie-upgrade. Een ontwikkelaar die overstapt van versie 1.0 naar 2.0, kan beginnen met het opslaan van waarden onder een sleutel met een prefix, zoals MY_MODULE_WIDTH. Om de oude, niet-geprefixte vermeldingen "op te schonen", voegen ze een delete-aanroep toe aan de uninstall-routine, in de veronderstelling dat ze alleen legacy-gegevens verwijderen. In werkelijkheid verwijderen ze ook alles wat andere extensies onder dezelfde generieke sleutel hebben opgeslagen.

Wat de audit aan het licht bracht

Een audit van 57 publieke module-repositories onthulde een terugkerend patroon:

  • Veel modules gebruiken generieke sleutels zoals "width", "height" of "API_DATE_FROM" zonder een prefix die afgeleid is van de naam van de module.
  • Verschillende uninstall-methoden bevatten Configuration::deleteByName-aanroepen die gericht zijn op deze generieke sleutels.
  • Het probleem is niet beperkt tot één enkele ontwikkelaar of een bepaald type module; het ontwerp van de gedeelde tabel maakt het een systemisch risico.

De audit vond geen logs of foutmeldingen die een winkelier zouden waarschuwen dat de configuratie van een andere module was verwijderd. Het enige symptoom is een plotseling verlies van instellingen, wat de handelaar kan toeschrijven aan een cacheprobleem of een bug in de eigen code.

Veiligere praktijken voor moduleontwikkelaars

  1. Gebruik namespaces voor elke sleutel – voeg de technische naam van de module toe aan elke configuratiesleutel (bijv. my_module_width). Dit creëert een unieke identifier zonder afhankelijk te zijn van een aparte kolom voor eigenaarschap.
  2. Vermijd het verwijderen van oude, niet-geprefixte sleutels – het achterlaten van een paar verouderde rijen in de tabel kost vrijwel niets aan opslagruimte en elimineert het risico op nevenschade.
  3. Controleer het eigenaarschap vóór verwijdering – als verwijdering echt noodzakelijk is, controleer dan eerst of de waarde van de sleutel door je eigen code is ingesteld (sla bijvoorbeeld een marker-waarde op die alleen jouw module kent).
  4. Audit uninstall-methoden – zoek in de codebase naar deleteByName-aanroepen. Elke instantie moet worden gecontroleerd om te bevestigen dat de sleutel een unieke namespace heeft.
  5. Documenteer de naamgevingsconventie – neem een korte richtlijn op in de README van de module, zodat toekomstige bijdragers het belang van geprefixte sleutels begrijpen.

Testen op onbedoelde verwijderingen tussen modules

Een praktische manier om de bug te vangen voordat deze een live shop bereikt:

  • Seed de configuratietabel met een sleutel die bij een andere module hoort (bijv. other_module_setting => test).
  • Voer de uninstall-routine van de module uit in een gecontroleerde omgeving.
  • Controleer (assert) of de toegevoegde sleutel nog steeds bestaat nadat de uninstall is voltooid.

Het automatiseren van deze controle in de unit-testsuite van de module zorgt ervoor dat elke toekomstige wijziging die een verloren deleteByName-aanroep introduceert, de test doet falen, wat een review uitlokt.

Waar winkeliers op moeten letten

Winkelbezitters zien zelden de interne database-rijen, maar ze kunnen het symptoom wel opmerken: nadat een module is uitgeschakeld of verwijderd, keert een andere extensie plotseling terug naar de standaardinstellingen. Als dat gebeurt, vraag de ontwikkelaar dan om te controleren of de uninstall-code van de module de globale configuratietabel respecteert. Vraag om een lijst van alle configuratiesleutels die de module gebruikt; elke sleutel zonder duidelijke prefix is een waarschuwingssignaal.

Kernpunt

Het ontwerp van PrestaShop maakt de configuratietabel een gedeelde bron, en een onvoorzichtige de-installatieroutine kan de instellingen van een andere module spoorloos wissen. Door keys te voorzien van een namespace, agressieve opschoning te vermijden en een eenvoudige test toe te voegen die externe vermeldingen beschermt, kunnen ontwikkelaars stilzwijgend gegevensverlies voorkomen en de webshops van handelaren stabiel houden. De benodigde inspanning is minimaal, maar de kosten van een verloren instelling — klachten van klanten, supporttickets en reputatieschade — kunnen vele malen hoger liggen.