دليل تقني

تصميم Workflow في Pimcore للمؤسسات: البنية اللي تتحمل 20 محرر

كيف تصمم workflows في Pimcore لفرق المؤسسات. فصل الحالة بثلاث طبقات، ملكية الحقول، التحكم بالأحداث، إدارة الإصدارات، وأمان استيراد ERP.

25 مارس 202624 دقيقة للقراءةفريق هندسة أورنتس

المشكلة اللي ما حدا يحكي عنها

كل مشروع Pimcore بيبدأ بنفس الطريقة. كم منتج، فريق محتوى من ثلاث أشخاص، كل شي يدار من خلال واجهة الإدارة. النشر يعني ضغطة زر. الحياة بسيطة.

بعدين النظام يكبر. عشرين محرر عبر أقسام متعددة. نظام ERP يدفع آلاف تحديثات المنتجات يومياً. عمال خلفية يولدون صور مصغرة وملفات PDF وتحديثات فهرس البحث. قنوات مخرجات متعددة تسحب منتجات لجماهير مختلفة. محرك بحث يزامن كل تغيير.

وفجأة كل شي ينكسر بطرق ما حدا توقعها.

شفنا هالشي بأعيننا بمشروع PIM مؤسسي لمصنع B2B في منطقة DACH. النظام كان فيه عدة event subscribers، ومجموعة عمال async، وتكامل ERP يدفع استيرادات يومية، وقنوات مخرجات متعددة تخدم احتياجات عمل مختلفة. الفريق وصل لأكثر من 20 محرر، والبنية الأصلية كانت تنهار تحت وزنها.

المشكلة الجذرية: save() في Pimcore مصمم لمحررين بشريين، مش لأنظمة مؤسسية فيها عمليات أوتوماتيكية متعددة تتنافس على نفس البيانات.

هالمقالة تغطي كيف أعدنا تصميم بنية workflow من الصفر. الأنماط هنا تنطبق على أي مشروع Pimcore يتجاوز الأساسيات. للسياق الأوسع عن كيف نتعامل مع بنية الأنظمة وتنفيذات PIM، هالأدلة تعطي خلفية مفيدة.

ليش نموذج Pimcore الافتراضي ينكسر على نطاق واسع

آلية حفظ الكائنات في Pimcore تشتغل من خلال نقطة دخول واحدة:

$product->save();

هالشي يطلق سلسلة سلوكيات ضمنية:

save()
  -> PRE_UPDATE event fires (all subscribers, synchronous)
  -> update() persists FULL object state to published tables
  -> saveVersion() creates a version snapshot
  -> POST_UPDATE event fires (all subscribers, synchronous)
  -> Each subscriber may dispatch async messages
  -> Each message handler may call save() again
  -> Loop until supervisor or error breaks it

كل save() يحفظ الكائن كامل. مش الحقل اللي تغير. الكائن كامل. هالتصميم يشتغل تمام للمحررين البشريين اللي يسوون تغييرات بين فترة وفترة. بس ينفشل لما يكون عندك:

المشكلةشو يصيرالأثر الحقيقي
ما في تحكم بالتزامنعاملين يحملون نفس المنتج، كل واحد يعدل حقل، الاثنين يحفظون. الحفظ الثاني يكتب فوق تغيير العامل الأول.أصول مولّدة ترجع بصمت بعد ما عامل ثاني يشتغل
عواصف الأحداثحفظة وحدة تطلق عدة subscribers، كل واحد يرسل رسائل، كل رسالة تسبب حفظات إضافيةاستيراد منتجات يولد آلاف الحفظات غير الضرورية
انفجار الإصداراتكل حفظة من عامل تنشئ إصدار ما حدا يحتاجهآلاف الإصدارات لكل منتج، تخزين مستهلك، تاريخ بلا فائدة
ما في ملكية حقولتعديلات المحتوى وكتابات النظام تمر من نفس مسار save()استيراد ERP يكتب فوق حقول منسقة يدوياً
ما في تحكم بالآثار الجانبيةVersion::disable() هو علم static عام، مش محدود النطاق أو قابل للتركيبتعطيل الإصدارات بعامل واحد يأثر على كل العمال بنفس العملية

قبل ما نصلح هالمشاكل، استيراد المنتجات كان ياخذ ساعات ويولد طوابير رسائل ضخمة. بعد إعادة تصميم البنية، نفس الاستيراد يتم بدقائق مع آثار جانبية متحكم فيها وقابلة للتوقع.

نموذج الحالة بثلاث طبقات

القرار المعماري الجوهري: افصل ثلاث مسؤوليات Pimcore يخلطهم بوحدة.

┌─────────────────────────────────────────────────────────┐
│                                                         │
│  Layer 1: OPERATIONAL WORKFLOW (human process)          │
│  ┌─────┐  ┌───────────┐  ┌──────────┐  ┌──────────┐  │
│  │ NEW │─▶│IN_PROGRESS│─▶│IN_REVIEW │─▶│ APPROVED │  │
│  └─────┘  └───────────┘  └──────────┘  └────┬─────┘  │
│                  ▲            │               │        │
│                  └────────────┘               │        │
│                (feedback loop)                ▼        │
│                                        ┌───────────┐  │
│                                        │ PUBLISHED  │  │
│                                        └─────┬─────┘  │
│                                                        │
├────────────────────────────────────────────────────────┤
│                                                        │
│  Layer 2: PUBLICATION STATE (Pimcore built-in)         │
│  published = true  → product is live on website        │
│  published = false → not visible on any channel        │
│  Draft versions → edits saved without publishing       │
│                                                        │
├────────────────────────────────────────────────────────┤
│                                                        │
│  Layer 3: CHANNEL ELIGIBILITY (computed, NOT stored)   │
│  isChannelReady = published=true                       │
│                   AND workflow=PUBLISHED                │
│                   AND ChannelValidator.passes()         │
│                   AND not archived                      │
│                                                        │
└─────────────────────────────────────────────────────────┘

الطبقة 1: سير العمل التشغيلي

سير عمل واحد على كلاس Product باستخدام تكامل Symfony Workflow في Pimcore. النوع: state_machine (مكان واحد بالمرة).

هالسير عمل يجاوب: مين يملك المنتج هلأ؟ بأي مرحلة؟ مين يتحرك بعدين؟

pimcore:
    workflows:
        product_lifecycle:
            enabled: true
            label: 'Product Lifecycle'
            type: 'state_machine'
            supports:
                - 'Pimcore\Model\DataObject\Product'
            initial_markings:
                - 'new'
            marking_store:
                type: state_table

            places:
                new:
                    label: 'New'
                    color: '#90CAF9'
                    permissions:
                        - save: true
                          publish: false
                in_progress:
                    label: 'In Progress'
                    color: '#FFE082'
                    permissions:
                        - save: true
                          publish: false
                in_review:
                    label: 'In Review'
                    color: '#FFAB91'
                approved:
                    label: 'Approved'
                    color: '#A5D6A7'
                published:
                    label: 'Published'
                    color: '#4CAF50'
                archived:
                    label: 'Archived'
                    color: '#BDBDBD'

التمييز الأساسي اللي أغلب الفرق تفوته: ما في حالة REJECTED. الرفض هو انتقال رجوعاً لـ IN_PROGRESS مع تعليق إلزامي يتخزن في Notes & Events. هالشي يخلي سير العمل نظيف وعملية المراجعة حلقة، مش طريق مسدود.

الطبقة 2: حالة النشر

هاي مش سير عمل. هاي تستخدم آليات Pimcore الموجودة:

  • published = true يتحكم بالظهور على الموقع
  • نظام الإصدارات في Pimcore ينشئ لقطات مع كل حفظة
  • إصدارات المسودة تخلي المحررين يشتغلون بدون ما يأثروا على الموقع الحي
  • النشر يرفع إصدار معين ليكون الحي

هالشي يعطي سلوك شبيه بـ Git:

مفهوم Gitالمقابل في Pimcore
فرع mainالإصدار المنشور حالياً
فرع featureإصدار مسودة (محفوظ بدون نشر)
دمج في mainإجراء النشر (يرفع المسودة للحي)
تاريخ commitsتاريخ الإصدارات في تبويب Versions

لما محرر يحفظ بدون نشر، بس إصدار مسودة ينشأ. جداول النشر تبقى بدون تغيير. الموقع الحي ما يشوف أبداً شغل نص مكمل.

الطبقة 3: أهلية القنوات (محسوبة، مش مخزنة)

هذا القرار اللي ألغى فئة كاملة من الأخطاء. جاهزية القناة (هل المنتج مؤهل لقناة مخرجات معينة مثل تغذية سوق، أو خط تصدير، أو واجهة شريك) مش حقل مخزن على المنتج. هي محسوبة من الحقيقة الحالية.

class ProductOutputEligibility
{
    public function isChannelReady(Product $product, string $channel): bool
    {
        return $product->isPublished()
            && $this->workflowState->getCurrentState($product) === 'published'
            && !$this->workflowState->isArchived($product)
            && $this->channelValidator->isValid($product, $channel);
    }

    public function getBlockingErrors(Product $product, string $channel): array
    {
        $errors = [];
        if (!$product->isPublished()) {
            $errors[] = 'Product must be published';
        }
        // ... فحص حالة سير العمل، الأرشفة
        return array_merge($errors, $this->channelValidator->getErrors($product, $channel));
    }
}

ليش المحسوبة أحسن من حقل حالة مخزن:

حقل مخزننتيجة محسوبة
ممكن يصير قديم (يقول READY بس الصورة المطلوبة محذوفة)دايماً يعكس الحقيقة الحالية
يحتاج إعادة ضبط يدوية بعد التغييراتما يحتاج إعادة ضبط، يتحسب عند الطلب
لازم يتزامن مع حالة سير العملما يحتاج تزامن
ينشئ حقيقة مكررةمصدر حقيقة واحد: البيانات الفعلية
يحتاج ترحيل لقواعد جديدةبس حدّث منطق المدقق

النظام القديم كان يستخدم حيل حيث المنتجات كان لازم يلغوا نشرها ليجهزوها لقنوات معينة. هالشي كان يكسر ظهور الموقع كل مرة. المقاربة المحسوبة تقتل هالنمط نهائياً.

لمزيد عن كيف نفكر بـخطوط أنابيب هندسة البيانات والمخرجات الخاصة بكل قناة، صفحة الخدمة تلك تغطي نهجنا الأوسع.

ملكية الحقول: مين يقدر يكتب شو

القرار المعماري الحاسم الثاني: مش كل الحقول متساوية. بعضها للمحررين، بعضها للآلات، بعضها للاثنين مع قواعد.

pimtx:
    field_ownership:
        Product:
            editor_owned:
                - name
                - description
                - shortDescription
                - images
            system_owned:
                - thumbnail
                - searchIndex
                - checksum
                - lastSyncTimestamp
            shared:
                - categories
                - price
                - availability
                - status
المجالالمالكأمثلةمسار التعديل
ملك المحررمستخدمو الإدارةالاسم، الوصف، الصورحفظ Pimcore العادي
ملك النظامالعمال والتكاملاتصور مصغرة، فهرس البحث، checksumsطبقة المعاملات
مشتركالاثنين، مع سياسة تعارضالفئات، الأسعار، التوفرطبقة المعاملات مع استراتيجية تعارض

ملكية الحقول تحدد:

  • أي حقول تطلق كشف التغييرات لأي عمليات
  • أي استراتيجيات حل تعارض تنطبق
  • هل التحديث الجزئي آمن لحقل معين
  • شو يظهر في العرض التجاري مقابل العرض التقني للتدقيق

بدون ملكية حقول، استيراد ERP يقدر يكتب فوق محتوى منسق يدوياً. مع الملكية، الاستيراد يلمس بس الحقول اللي يملكها، والحقول المشتركة تستخدم استراتيجية تعارض مضبوطة (إعادة محاولة، تخطي، فشل، أو دمج إذا آمن).

هالنمط أساسي في كيف بنينا PimTx، طبقة المعاملات والتزامن مفتوحة المصدر لـ Pimcore. فريق الاستشارات ساعد عدة عملاء Pimcore مؤسسيين ينفذون هالنمط بالضبط.

التحكم بمشتركي الأحداث: إيقاف التسلسل

النمط الأخطر في أنظمة Pimcore المؤسسية هو تسلسل الحفظ. حفظة وحدة تطلق عدة event subscribers. كل واحد يرسل رسائل async. كل معالج رسائل يحمل المنتج، يعدل حقل، ويحفظ. كل حفظة تطلق كل الـ subscribers مرة ثانية.

الـ EventSubscriberSupervisor هو singleton محدود النطاق بالعملية يتحكم بأي subscribers نشطة:

// تعطيل كل event subscribers على مستوى التطبيق قبل حفظة العامل
$this->eventSubscriberSupervisor->disableAll();

try {
    $product->setQrCode($generatedAsset);
    $product->save();
} finally {
    $this->eventSubscriberSupervisor->enableAll();
}

ترتيب العمليات مهم. لو غلطت فيه بتنشئ نفس الحلقة اللي تحاول تمنعها:

// غلط: الأحداث تتفعل مجدداً قبل الحفظ
$this->eventSubscriberSupervisor->disableAll();
try {
    // شغل...
} finally {
    $this->eventSubscriberSupervisor->enableAll(); // تفعلت هنا
}
$product->save(); // الحفظ يطلق الأحداث، الحلقة تبدأ

// صح: الحفظ يصير داخل نطاق التعطيل
$this->eventSubscriberSupervisor->disableAll();
try {
    $product->setQrCode($generatedAsset);
    $product->save(); // حفظ هنا، الأحداث مكبوتة
} finally {
    $this->eventSubscriberSupervisor->enableAll();
}

هذا محدود بالعملية. يعطل subscribers بس ضمن نفس عملية PHP. حاويات عمال ثانية عندها نسخ supervisor خاصة فيها. بس لأن الحفظة ما ترسل رسائل جديدة (الـ subscribers معطلة)، ما في رسائل جديدة توصل عمال ثانيين.

إدارة الإصدارات: منع الانفجار

بالنظام الأصلي، كل حفظة عامل كانت تنشئ إصدار. مع 6 عمال يعالجون كل تغيير منتج، تعديل بشري واحد ولّد 6+ إصدارات ما حدا احتاجها. مع الوقت، المنتجات جمعت آلاف الإصدارات، تستهلك تخزين وتخلي تاريخ الإصدارات بلا فائدة للتدقيق الفعلي.

الحل: حارس إصدارات محدود النطاق يكبت الإصدارات غير الضرورية أثناء عمليات النظام.

// حارس إصدارات PimTx محدود النطاق (بعداد مراجع)
$versionGuard = $this->versionGuardFactory->create();
$versionGuard->suppress();

try {
    // عمليات نظام متعددة، ما في إصدارات تنشأ
    $product->setThumbnail($thumbnailAsset);
    $product->save();

    $product->setChecksum($newChecksum);
    $product->save();
} finally {
    $versionGuard->restore();
}

بخلاف Version::disable() العام في Pimcore، هالحارس بعداد مراجع ومحدود النطاق. العمليات المتداخلة تشتغل صح. حارس واحد يستعيد ما يرجع بالغلط يفعل الإصدارات لعملية أب لسا تحتاجهم مكبوتين.

المقاربةالنطاقالتداخلالأمان
Version::disable() (Pimcore)علم static عاممكسور (أي enable() يعيد التفعيل للكل)خطير مع عمال متزامنين
حارس إصدارات محدود النطاق (PimTx)لكل عملية، بعداد مراجعصحيح (يستعيد بس لما كل الحراس يتحررون)آمن للعمال المتزامنين

النتيجة: حفظات المحررين تنشئ إصدارات (مسار التدقيق محفوظ). حفظات العمال تنشئ سجلات عمليات بدلاً (مراقبة كاملة بدون تضخم الإصدارات). تقدر تشوف بالضبط شو سوى كل عامل، متى، وعلى أي حقول، بدون ما تتصفح 4,000 إدخال إصدار بلا فائدة.

أمان استيراد ERP

الجزء الأكثر حساسية سياسياً بأي بنية PIM: شو يصير لما نظام ERP يدفع بيانات.

بالنظام الأصلي، استيرادات ERP كانت تكتب فوق كل شي. أوصاف منسقة يدوياً، فئات مضبوطة بعناية، حالة تحريرية. كلهم يروحون بعد الاستيراد الليلي.

الحل المعماري يجمع ملكية الحقول مع قواعد خاصة بالاستيراد:

# ERP import field mapping
# حقول محمية (مش بالتعيين، الاستيراد ما يقدر يلمسها):
#   - description (ملك المحرر)
#   - shortDescription (ملك المحرر)
#   - images (ملك المحرر)
#   - workflow state (محكومة بالعملية)

# حقول مستوردة (ملك ERP):
#   - erpId (مفتاح التعرف)
#   - sku
#   - dimensions
#   - weight
#   - ean

# حقول مشتركة (الاستيراد يحدث، بس كشف التغييرات ينطبق):
#   - categories (استراتيجية دمج)
#   - price (كتابة فوق مع إشعار)
#   - availability (كتابة فوق مع فحص أثر التغيير)

لما استيراد ERP يغير حقل حرج تجارياً على منتج منشور، كشف أثر التغيير يحدده تلقائياً للمراجعة. الاستيراد ما يحتاج يعرف عن سيرات العمل التحريرية. نظام ملكية الحقول يتعامل معه.

ضمانات حرجة:

  1. أهلية القنوات تعيد الحساب تلقائياً (محسوبة، مش مخزنة)
  2. حالة سير العمل ما تنضبط أبداً من الاستيرادات
  3. الحقول اللي يملكها المحرر مش بتعيين الاستيراد
  4. الحقول المشتركة تستخدم استراتيجيات تعارض مع إشعار
  5. الـ EventSubscriberSupervisor يمنع التسلسلات اللي يطلقها الاستيراد

شو يصير لما منتج حي ينعدل

هذا أهم تدفق من ناحية المستخدم. محرر يحتاج يحدث منتج حي بدون ما يكسر الموقع أو أي قناة مخرجات.

1. المنتج بحالة PUBLISHED، published=true، حي على الموقع
2. المحرر يفتح المنتج، يعدل الوصف
3. المحرر يضغط "Save" (مش "Publish")
4. Pimcore ينشئ إصدار مسودة فقط
5. جداول النشر تبقى بدون تغيير
6. الموقع يستمر يقدم الإصدار المنشور الحالي
7. كشف أثر التغيير يشتغل:
   - إذا حقول حرجة تجارياً تغيرت: الفرق المعنية تتبلغ
   - إذا بس حقول داخلية/SEO تغيرت: ما في إشعار
8. المحرر يكمل شغل على المسودة
9. لما يكون جاهز: يقدم للمراجعة (IN_REVIEW)
10. المراجع يوافق: انتقال لـ APPROVED
11. مدير الإصدار ينشر: المسودة تترفع للحي
12. سير العمل يرجع لـ PUBLISHED
13. أهلية القنوات تعيد الحساب تلقائياً

الموقع ما يشوف أبداً شغل نص مكمل. ما في قناة مخرجات تنكسر من تغييرات قيد العمل. كل شي بإصدارات، قابل للتدقيق، وقابل للتراجع.

هذا بالضبط نوع بنية البرمجيات المخصصة اللي نبنيها لعملاء المؤسسات. إذا تحتاج مساعدة بتخطيط إعادة تصميم سير العمل، اطلب عرض سعر أو تحدث مع فريق الاستشارات.

كشف أثر التغيير

مش كل التغييرات متساوية. محرر يصلح خطأ إملائي بنص SEO ما المفروض يطلق مراجعة قنوات. محرر يستبدل صورة المنتج الرئيسية، هذا لازم.

نظام كشف التغييرات يصنف التغييرات حسب الأثر:

class ChangeImpactClassifier
{
    private const BUSINESS_CRITICAL_FIELDS = [
        'description',
        'shortDescription',
        'images',
        'technicalAttributes', // Classification Store
        'price',
        'availability',
        'categories',
    ];

    private const NON_IMPACTFUL_FIELDS = [
        'seoText',
        'searchKeywords',
        'internalTags',
        'lastSyncTimestamp',
    ];

    public function classify(Product $product, array $changedFields): ChangeImpact
    {
        $critical = array_intersect($changedFields, self::BUSINESS_CRITICAL_FIELDS);

        if (count($critical) > 0) {
            return ChangeImpact::BUSINESS_CRITICAL;
        }

        $nonImpactful = array_intersect($changedFields, self::NON_IMPACTFUL_FIELDS);
        if (count($nonImpactful) === count($changedFields)) {
            return ChangeImpact::NON_IMPACTFUL;
        }

        return ChangeImpact::STANDARD;
    }
}

التنفيذ: subscriber لـ PRE_UPDATE يحمل بيانات الإصدار السابق، يقارن حقل بحقل مع الحالة الحالية، يصنف التغييرات حسب الأثر التجاري، ويخزن ملخص التغيير كـ Note على الكائن.

قواعد التحقق لجاهزية القنوات

بما إن أهلية القنوات محسوبة، المدقق يحدد شو يعني "جاهز" لكل قناة:

class ChannelValidator
{
    public function isValid(Product $product, string $channel): bool
    {
        return count($this->getErrors($product, $channel)) === 0;
    }

    public function getErrors(Product $product, string $channel): array
    {
        $errors = [];

        // متطلبات مشتركة لكل القنوات
        if (!$product->getMainImage()) {
            $errors[] = 'At least one product image required';
        }

        if (empty($product->getDescription())) {
            $errors[] = 'Description text required in at least one locale';
        }

        // متطلبات خاصة بالقناة
        if ($channel === 'marketplace') {
            if (empty($product->getPrice())) {
                $errors[] = 'Price is required for marketplace export';
            }
            if (empty($product->getCategories())) {
                $errors[] = 'At least one category required for marketplace';
            }
        }

        return $errors;
    }
}

الواجهة تبين بالضبط شو يمنع الأهلية لكل قناة. ما في تخمين، ما في "اسأل مدير القناة." المنتج إما يمر بالتحقق أو النظام يقلك ليش ما مر.

لكيف نتعامل مع أنماط تحقق مشابهة في تصميم سير عمل الذكاء الاصطناعي وحوكمة الذكاء الاصطناعي، هالأدلة تغطي أوجه التشابه.

طبقة المعاملات (PimTx)

كل هالأنماط تتجمع في PimTx، طبقة المعاملات والتزامن اللي بنيناها كـ Symfony bundle. كل كتابة نظام تصير عملية صريحة:

// بدل $product->save() مباشرة
$result = $this->transactionManager->execute(
    OperationContext::for($product)
        ->name('qr_code_generation')
        ->systemField('qrCode')
        ->lock(LockType::OPERATION)
        ->version(VersionPolicy::SUPPRESS_PIMCORE_VERSION)
        ->events(EventPolicy::SUPPRESS)
        ->conflict(ConflictStrategy::RETRY)
        ->maxRetries(3)
        ->idempotencyKey("qr:{$product->getId()}:{$locale}")
        ->mutate(function (Product $p) use ($qrAsset) {
            $p->setQrCode($qrAsset);
        })
);

if ($result->wasSkipped()) {
    // تكافؤ: نفس العملية اشتغلت من قبل
    $this->logger->info('QR generation skipped', [
        'reason' => $result->skipReason,
        'product_id' => $product->getId(),
    ]);
}

شو يسوي هالتصريح:

  • يأخذ قفل محدود بالعملية (يمنع توليد QR متزامن لنفس المنتج)
  • يفحص التكافؤ (نفس العملية بنفس المفتاح ما تشتغل مرتين)
  • يكبت إنشاء الإصدارات (العملية تسجل بتدقيق PimTx، مش إصدارات Pimcore)
  • يكبت مشتركي الأحداث (يمنع الحفظات المتسلسلة)
  • يعيد المحاولة عند التعارض (إذا عامل ثاني عدل المنتج بين التحميل والحفظ)
  • يرجع نتيجة منظمة (نجاح، تخطي، تعارض محلول، أو فشل)

قاعدة الحوكمة: أي تعديل غير محرري يوصل Pimcore من خلال save() غير مدار يعتبر خارج السياسة. كود النظام لازم يمر بطبقة المعاملات. بدون هالقاعدة، الفرق ببطء تتجاوز الطبقة وتعيد إنشاء نفس الحوادث.

لمزيد عن كيف نراقب أنظمة زي هاي في الإنتاج، شوف دليل مراقبة الذكاء الاصطناعي اللي يغطي أنماط تسجيل منظمة وتتبع مشابهة.

بنية الإشعارات

سير عمل Pimcore يدعم الإشعارات على الانتقالات:

الحدثمين يتبلغالقناة
المنتج يدخل IN_REVIEWدور المراجعإشعار Pimcore + بريد إلكتروني
المنتج موافق عليهمالك المنتج / المحررإشعار Pimcore
تغيير حرج تجارياً مكتشففرق القنوات المعنيةبريد إلكتروني مع ملخص التغييرات
منتج منشور تم تعديله (مسودة أُنشئت)المحرر المسؤولإشعار Pimcore
المنتج منشورمدير الإصدارإشعار Pimcore
الاستيراد يغير حقول مشتركةمالك الحقلبريد إلكتروني مع الفرق

الإشعارات تحمل سياق: شو تغير، مين غيره، أي حقول تأثرت، ومستوى الأثر التجاري. مش بس "المنتج 12345 تحدث."

أخطاء شائعة

  1. استخدام عدة workflows. سير عمل واحد لكل كلاس منتج. عدة workflows تخلق تعارضات حالة وارتباك صلاحيات. جاهزية القنوات تُعالج بأهلية محسوبة، مش بسيرات عمل منفصلة.

  2. تخزين حالة القناة كحقل. أي حقل حالة مخزن يصير قديم لحظة ما حدا يحذف صورة أو يغير سمة مطلوبة. احسب الأهلية من الحقيقة الحالية.

  3. تخطي ملكية الحقول. بدون ملكية حقول، كل استيراد وعامل ومحرر يتنافسون على نفس الحقول من خلال نفس مسار save(). حدد مين يملك شو قبل أول سطر كود.

  4. استخدام Version::disable() بشكل عام. هالعلم static العام ينكسر لما عمليات متعددة تشتغل بالتزامن. استخدم حراس إصدارات بعداد مراجع ومحدودي النطاق.

  5. ترك الاستيرادات تلمس حالة سير العمل. استيرادات ERP لازم تحدث حقول بيانات، مش حالة العملية. حالة سير العمل تتحكم فيها الانتقالات البشرية وكشف التغييرات الأوتوماتيكي.

  6. إطلاق مراجعة على كل تغيير. صنف التغييرات حسب الأثر. تحديثات نص SEO ما لازم تطلق مراجعات تجارية. بس تغييرات الحقول الحرجة تجارياً لازم تسويها.

  7. عدم فصل حفظة المحرر عن حفظة النظام. أكبر مصدر لعواصف الأحداث. حفظات العمال وحفظات المحررين تحتاج مسارات مختلفة بسياسات آثار جانبية مختلفة.

  8. تجاهل حلقة الحفظ. subscriber واحد غير متحكم فيه يقدر يحول استيراد منتجات لكارثة ساعات. الـ EventSubscriberSupervisor مش اختياري.

خارطة طريق التنفيذ

المرحلة 1: الأساس (سير العمل + أهلية القنوات)

  • عرّف حالات وانتقالات سير العمل بـ YAML
  • نفذ أهلية قنوات محسوبة (استبدل حقول الحالة المخزنة)
  • اضبط صلاحيات سير العمل حسب الحالة
  • كشف أثر التغيير الأساسي (حرج تجارياً مقابل غير مؤثر)

المرحلة 2: الحوكمة (ملكية الحقول + التحكم بالأحداث)

  • عرّف سجل ملكية الحقول (محرر/نظام/مشترك لكل حقل)
  • نفذ EventSubscriberSupervisor
  • أضف حراس إصدارات محدودي النطاق لعمليات العمال
  • اضبط حماية حقول استيراد ERP

المرحلة 3: الإنتاج الكامل (طبقة المعاملات + الإشعارات)

  • انشر طبقة معاملات PimTx
  • أضف تكافؤ لكل عمليات العمال
  • نفذ بنية الإشعارات
  • تسجيل تدقيق كامل بعروض تجارية وتقنية
  • اختبار انحدار عبر كل العمال والتكاملات

شوف نظرة عامة على الثقة والامتثال لكيف نوثق ضمانات النظام لعملاء المؤسسات.

النقاط الأساسية

  • افصل ثلاث مسؤوليات بثلاث طبقات. سير العمل يتحكم بالعملية. علم النشر يتحكم بظهور الويب. أهلية القنوات محسوبة من الحقيقة الحالية. خلطهم ينشئ حيل تكسر كل شي.

  • ملكية الحقول مش اختيارية على نطاق واسع. بدونها، كل عامل واستيراد ومحرر يكتبون فوق شغل بعض من خلال نفس مسار save(). حدد مين يملك أي حقول قبل ما تكتب أول انتقال سير عمل.

  • التحكم بمشتركي الأحداث يمنع الكوارث المتسلسلة. حفظة غير متحكم فيها وحدة تقدر تطلق آلاف الرسائل. الـ EventSubscriberSupervisor هو الإصلاح الأكثر تأثيراً لأداء Pimcore على نطاق واسع.

  • احسب، لا تخزن جاهزية القنوات. أي حقل حالة مخزن يصير قديم. احسب الأهلية من حالة النشر الحالية، حالة سير العمل، وقواعد التحقق. ما في تزامن مطلوب، ما في بيانات قديمة ممكنة.

  • حراس الإصدارات يحفظون مسارات التدقيق بدون الانفجار. حفظات المحررين تنشئ إصدارات. حفظات العمال تنشئ سجلات عمليات. نفس المراقبة، 1/100 من التخزين.

  • غلّف Pimcore، لا تفرعه. PimTx يحكم كل كتابات النظام من خلال نموذج عمليات صريح. يغلف $object->save() بحراس. ما يستبدل أو يتجاوز نواة Pimcore. الترقيات تبقى نظيفة.

بنينا PimTx كـ Symfony bundle مفتوح المصدر لهالأنماط بالضبط. إذا تشغل مشروع Pimcore مؤسسي وتواجه مشاكل التوسع هاي، خدمات الذكاء الاصطناعي وهندسة البيانات عندنا تغطي الحزمة الكاملة من مراجعة البنية لنشر الإنتاج.

جاهز تعيد تصميم بنية سير عمل Pimcore عندك؟ تحدث مع فريقنا أو اطلب عرض سعر.

المواضيع المغطاة

Pimcore workflowPimcore للمؤسساتSymfony workflow Pimcoreتصميم سير عمل PIMPimcore state machineإصدارات Pimcoreملكية الحقولPimTx

جاهز لبناء أنظمة ذكاء اصطناعي جاهزة للإنتاج؟

فريقنا متخصص في بناء أنظمة ذكاء اصطناعي جاهزة للإنتاج. خلينا نحكي كيف نقدر نساعد.

ابدأ محادثة