Deep DiveTopics.
تعمّق في أربع مواضيع بيتكرروا كتير في الإنترفيو: الفرق بين Preference والـ Plugin، الـ GraphQL، الـ Headless integration، ومكوّنات الـ Module بالتفصيل.
الـ Preference بيستبدل class كامل في di.xml، ولو أكتر من module عملوا preference لنفس الـ class واحد بس بيكسب، عشان كده الـ Plugin غالبًا أأمن لأنه بيعدّل method محددة وممكن يشتغل مع plugins تانية. والـ GraphQL محتاج schema و resolvers، والـ Headless معناه frontend منفصل بيتكلّم مع Magento بالـ APIs.
Preference vs Plugin
أشهر سؤال في إنترفيوهات Magento. الاتنين بيغيّروا سلوك، بس بطريقة وخطورة مختلفة تمامًا.
الـ Preference بيستبدل الـ class بالكامل. الـ Plugin بيتدخّل حوالين method محددة من غير ما يستبدل الـ class.
- يستبدل class بالكامل
- class واحد بس يقدر يكسب
- خطر التعارض بين الـ modules
- ممكن يكسّر الـ upgrades
- يورّث من الأصلي أو يعيد كتابته
- يتدخّل حوالين method
- كذا plugin يشتغلوا معًا
- آمن ومتعايش
- مرن مع الـ upgrades
- before / after / around
بتربط interface أو class بـ implementation بديلة. الكلاس البديل بيورّث من الأصلي عادةً.
<preference for="Magento\Catalog\Model\Product" type="Vendor\Module\Model\Product"/>
class Product extends \Magento\Catalog\Model\Product { public function getName() { // full override of the method return '[Custom] ' . parent::getName(); } }
نفس النتيجة بالظبط بس بأمان — من غير ما نستبدل الـ class، وكذا plugin يقدروا يشتغلوا مع بعض.
<type name="Magento\Catalog\Model\Product"> <plugin name="vendor_product_name" type="Vendor\Module\Plugin\ProductPlugin"/> </type>
class ProductPlugin { public function afterGetName( Product $subject, $result ) { return '[Custom] ' . $result; } }
GraphQL
الـ API الحديث اللي بيشغّل الـ headless والـ PWA. الـ client بيطلب الحقول اللي محتاجها بالظبط في request واحد.
بتعرّف الـ types والـ queries في etc/schema.graphqls، وبتربط كل query بـ resolver class.
type Query { getLog(id: Int!): Log @resolver(class: "Vendor\\Module\\Model\\Resolver\\Log") @doc(description: "Fetch a single log by id") } type Log { entity_id: Int message: String created_at: String }
الـ resolver هو الـ class اللي بيجيب الـ data فعليًا. بيورّث من ResolverInterface وبينفّذ resolve().
class Log implements ResolverInterface { public function __construct( private readonly LogRepositoryInterface $logRepository ) {} public function resolve( Field $field, $context, ResolveInfo $info, array $value = null, array $args = null ) { $log = $this->logRepository ->getById((int) $args['id']); return [ 'entity_id' => $log->getId(), 'message' => $log->getMessage(), ]; } }
{
getLog(id: 5) {
message
created_at
}
}
Headless Integration
فصل الـ frontend عن الـ backend. Magento بيبقى مصدر بيانات فقط، والواجهة بتتبني بأي تكنولوجي.
في الـ headless، Magento مبيرندرش الـ HTML. بيشتغل كـ backend / commerce engine بس، والـ frontend (React, Vue, Next.js...) بيتكلّم معاه عن طريق الـ APIs.
- أداء أسرع (خصوصًا PWA)
- حرية كاملة في الـ frontend
- نفس الـ backend لعدة قنوات
- تجربة موبايل ممتازة
- فرق frontend/backend مستقلة
- تعقيد وتكلفة أعلى
- مشروعين بدل واحد
- SEO محتاج SSR
- مميزات admin مبتشتغلش تلقائي
- صيانة أكتر
- PWA Studio — حل Adobe الرسمي، مبني على React + GraphQL.
- Vue Storefront — بديل شائع مبني على Vue / Nuxt.
- Next.js / custom — واجهة مخصّصة تتكلّم مع GraphQL مباشرة.
- الاعتماد الأساسي دايمًا على GraphQL للبيانات وREST لبعض العمليات.
الموديول بيتكوّن من إيه
تشريح كامل لكل جزء في الـ module وإيه وظيفته. لو فهمت ده، فهمت Magento كله.
أي module لازم يكون فيه على الأقل الملفين دول عشان Magento يعرفه.
ComponentRegistrar::register( ComponentRegistrar::MODULE, 'Vendor_Module', __DIR__ );
الـ etc/ هو قلب الـ config. الملفات ممكن تكون global أو جوّه area (frontend/, adminhtml/).
المواضيع الأربعة خلصت ✓
دلوقتي عندك صورة عميقة في: Preference vs Plugin، GraphQL، Headless، ومكوّنات الـ Module. دي من أكتر المواضيع اللي بيتعمّقوا فيها في الإنترفيو التقني.
نصيحة: اربط الأربعة ببعض في دماغك — الـ module بيعرّف GraphQL schema، الـ resolver بيستخدم service contracts، والـ headless بيستهلك الـ GraphQL ده.
خلّصت الدرس؟علّمه عشان تتابع تقدّمك في الكورس.
أسئلة شائعة
ما الفرق بين Preference و Plugin في Magento 2؟
الـ Preference بيستبدل الـ class بالكامل عن طريق di.xml، ولو كذا module عملوا preference لنفس الـ class واحد بس هيكسب. الـ Plugin بيتدخّل حوالين method محددة بـ before أو after أو around من غير ما يستبدل الـ class، وكذا plugin يقدروا يشتغلوا مع بعض. عشان كده الـ Plugin أأمن وأمرن مع الـ upgrades.
إمتى أستخدم Preference بدل Plugin في Magento 2؟
استخدم الـ Preference لما تحتاج تعدّل حاجة الـ plugin مايقدرش يلمسها، زي الـ constructor أو منطق كبير مترابط، أو لما تربط interface بـ implementation لأول مرة. غير كده فضّل الـ Plugin دايمًا، لأن الـ Preference ممكن يتعارض مع modules تانية ويكسّر الـ upgrades.
إزاي أعمل GraphQL query جديدة في Magento 2؟
بتعرّف الـ types والـ query في etc/schema.graphqls وتربط الـ query بـ resolver class عن طريق @resolver. الـ resolver بينفّذ ResolverInterface وmethod resolve()، بيستخدم الـ repository (service contracts) ويرجّع الـ data كـ array.
ليه الـ headless storefronts بتفضّل GraphQL عن REST؟
لأن GraphQL بيدّيك endpoint واحد والـ client بيطلب الحقول اللي محتاجها بالظبط في request واحد، بدل endpoints كتير وover-fetching وrequests متعددة في REST. ده بيقلل الـ round-trips، وده مهم جدًا للأداء على الموبايل والـ PWA.
يعني إيه Headless Magento وإيه مميزاته وعيوبه؟
في الـ headless، Magento مبيرندرش HTML وبيشتغل كـ commerce engine بس، والواجهة (React أو Vue أو Next.js) بتكلّمه عن طريق GraphQL وREST. مميزاته أداء أسرع وحرية كاملة في الـ frontend ونفس الـ backend لكذا قناة، وعيوبه تعقيد وتكلفة أعلى ومشروعين بدل واحد، والـ SEO محتاج SSR.
إيه الملفات الإجبارية لأي Module في Magento 2؟
أي module لازم يكون فيه registration.php اللي بيسجّله عن طريق ComponentRegistrar، وetc/module.xml اللي بيعرّف اسمه وترتيب تحميله (sequence). من غيرهم Magento مش هيشوف الـ module أصلًا، وبعدهم بتشغّل setup:upgrade عشان يتفعّل.
الـ checkout بيشتغل إزاي في Magento headless؟
الـ checkout بيتبني في الـ frontend، بس بيستدعي الـ GraphQL mutations بتاعة Magento زي addProductsToCart وplaceOrder. كل منطق الـ commerce بيفضل في Magento، والواجهة بس بتستدعيه.