جدول پیکربندی جهانی PrestaShop باعث میشود فرآیند حذف نصب (uninstall) یک ماژول به راحتی تنظیماتی را که متعلق به افزونههای کاملاً بیربط است، پاک کند. تنها یک فراخوانی Configuration::deleteByName('width') میتواند مقدار عرض سفارشی فروشگاه دیگری را پاک کند و باعث سردرگمی فروشنده و بیضرر به نظر رسیدن ماژول مقصر شود.
چرا جدول پیکربندی مشترک اهمیت دارد
PrestaShop تنظیمات هر ماژول را در یک جدول ذخیره میکند که فقط شامل یک کلید (key) و یک مقدار (value) است. این جدول ستونی ندارد که ثبت کند کدام ماژول یک ردیف را ایجاد کرده است و هیچ قرارداد نامگذاری خاصی را نیز اعمال نمیکند. در نتیجه، دو ماژول که از یک کلید یکسان استفاده میکنند — مثلاً "width" یا "API_DATE_FROM" — یک ردیف دیتابیس را میخوانند و مینویسند. آخرین عملیات نوشتن برنده است و هرگونه حذف بعدی، ردیف را برای هر دو طرف حذف میکند.
وقتی کد حذف نصب به ابزاری برای پاک کردن دادهها تبدیل میشود
یک متد حذف نصب معمولی به این صورت است:
public function uninstall()
{
return Configuration::deleteByName('width');
}
هدف این است که تنظیمات خودِ ماژول پاکسازی شود، اما چون کلید دارای فضای نام (namespace) نیست، این دستور هر ردیفی با نام "width" را حذف میکند. هیچ هشداری ثبت نمیشود، هیچ استثنایی (exception) پرتاب نمیشود؛ ردیف به سادگی ناپدید میشود. ماژول دیگرِ فروشنده بیصدا تنظیمات خود را از دست میدهد و ممکن است رفتارهای عجیبی نشان دهد.
این مشکل بهویژه در طول ارتقای نسخه بسیار وسوسهانگیز میشود. توسعهدهندهای که از نسخه ۱.۰ به ۲.۰ مهاجرت میکند، ممکن است شروع به ذخیره مقادیر تحت یک کلید دارای پیشوند (prefix) مانند MY_MODULE_WIDTH کند. برای «پاکسازی» ورودیهای قدیمی و بدون پیشوند، آنها یک فراخوانی حذف به فرآیند uninstall اضافه میکنند، با این باور که فقط در حال حذف دادههای قدیمی (legacy) هستند. در واقعیت، آنها هر افزونه دیگری را که تحت همان کلید عمومی ذخیره شده است نیز حذف میکنند.
آنچه بازرسی (audit) فاش کرد
بازرسی ۵۷ مخزن ماژول عمومی، یک الگوی تکرار شونده را نشان داد:
- بسیاری از ماژولها از کلیدهای عمومی مانند "width"، "height" یا "API_DATE_FROM" بدون هیچ پیشوندی که از نام ماژول مشتق شده باشد، استفاده میکنند.
- چندین متد uninstall شامل فراخوانیهای
Configuration::deleteByNameهستند که این کلیدهای عمومی را هدف قرار میدهند. - این مشکل محدود به یک توسعهدهنده یا نوع خاصی از ماژول نیست؛ طراحی جدول مشترک، آن را به یک ریسک سیستماتیک تبدیل کرده است.
در این بازرسی هیچ لاگ یا پیام خطایی یافت نشد که به صاحب فروشگاه هشدار دهد تنظیمات ماژول دیگری حذف شده است. تنها علامت، از دست رفتن ناگهانی تنظیماتی است که فروشنده ممکن است آن را به مشکل کش (cache) یا باگ در کد خود نسبت دهد.
روشهای ایمنتر برای توسعهدهندگان ماژول
- هر کلید را دارای فضای نام (Namespace) کنید – نام فنی ماژول را به ابتدای هر کلید پیکربندی اضافه کنید (مثلاً
my_module_width). این کار یک شناسه منحصربهفرد ایجاد میکند بدون اینکه به ستون مالکیت جداگانه متکی باشد. - از حذف کلیدهای قدیمی و بدون پیشوند خودداری کنید – باقی گذاشتن چند ردیف منسوخ در جدول، تقریباً هیچ هزینهای از نظر فضای ذخیرهسازی ندارد و خطر آسیبهای جانبی را از بین میبرد.
- مالکیت را قبل از حذف تأیید کنید – اگر حذف واقعاً ضروری است، ابتدا بررسی کنید که مقدار کلید توسط کد خودتان تنظیم شده باشد (برای مثال، یک مقدار نشانگر (marker) ذخیره کنید که فقط ماژول شما آن را میداند).
- متدهای uninstall را بازرسی کنید – در کد منبع به دنبال فراخوانیهای
deleteByNameبگردید. هر مورد باید بررسی شود تا تأیید گردد که کلید دارای فضای نام منحصربهفرد است. - قرارداد نامگذاری را مستند کنید – یک راهنمای کوتاه در فایل README ماژول قرار دهید تا مشارکتکنندگان آینده اهمیت کلیدهای دارای پیشوند را درک کنند.
تست برای حذفهای تصادفی بین ماژولها
یک راه عملی برای شناسایی باگ قبل از رسیدن به فروشگاه واقعی:
- جدول پیکربندی را با دادههای اولیه (seed) پر کنید؛ با کلیدی که متعلق به ماژول دیگری است (مثلاً
other_module_setting=>test). - فرآیند uninstall ماژول را در یک محیط کنترلشده اجرا کنید.
- تأیید کنید (Assert) که کلید اولیه پس از اتمام حذف نصب، همچنان وجود دارد.
خودکارسازی این بررسی در مجموعه تستهای واحد (unit-test) ماژول تضمین میکند که هر تغییر آتی که یک فراخوانی سرگردان deleteByName را معرفی کند، باعث شکست تست شده و منجر به بازبینی شود.
آنچه صاحبان فروشگاه باید مراقب باشند
صاحبان فروشگاه بهندرت ردیفهای داخلی دیتابیس را میبینند، اما میتوانند علامتها را تشخیص دهند: پس از غیرفعال کردن یا حذف نصب یک ماژول، افزونه دیگری ناگهان به تنظیمات پیشفرض بازمیگردد. اگر این اتفاق افتاد، از توسعهدهنده بخواهید تأیید کند که کد حذف نصب ماژول، به جدول پیکربندی جهانی احترام میگذارد. لیستی از تمام کلیدهای پیکربندی که ماژول استفاده میکند را درخواست کنید؛ هر کلیدی که فاقد یک پیشوند واضح باشد، یک نشانه خطر (red flag) است.
نکات کلیدی
طراحی PrestaShop باعث میشود جدول پیکربندی به یک منبع مشترک تبدیل شود و یک فرآیند نصبحذف بیدقت میتواند تنظیمات ماژول دیگری را بدون هیچ اثری پاک کند. توسعهدهندگان میتوانند با استفاده از فضای نام (namespacing) برای کلیدها، خودداری از پاکسازی تهاجمی و افزودن یک تست ساده برای محافظت از ورودیهای خارجی، از از دست رفتن بیخبر دادهها جلوگیری کرده و پایداری فروشگاههای بازرگانان را حفظ کنند. تلاش مورد نیاز بسیار ناچیز است، اما هزینه از دست رفتن یک تنظیم — شکایات مشتریان، تیکتهای پشتیبانی و آسیب به اعتبار — میتواند بسیار بیشتر باشد.
