بناء حزمة النقل دون تثبيت MODX



كتابة الحزم الخاصة بـ MODX ليست سهلة للمبتدئين ، وفي بعض الأحيان يكون للمطور ذي الخبرة وقت ممتع. لكن المبتدئ خائف ، والشخص ذو الخبرة يفهم :).

يتحدث هذا المنشور عن كيفية كتابة وإنشاء حزمة مكون لـ MODX دون تثبيت وتكوين MODX نفسه. المستوى أعلى من المتوسط ​​، لذلك قد تضطر إلى رف عقلك في بعض الحالات ، ولكن الأمر يستحق ذلك.

أطلب تفاصيل تحت القط.

ذات مرة ، عندما ظهر MODX Revolution للتو ، كان ذلك في الإصدار التجريبي المبكر ، لم يكن المطورين يعرفون بعد كيفية العمل به وكيفية كتابة المكونات الإضافية له. حسنًا ، فيما عدا الفريق الذي استحوذ على CMS. يجب أن أقول إن الفريق نجح جزئيًا وزود النظام بالقدرة على تجميع الحزم التي يمكن تثبيتها بعد ذلك من خلال المستودع ، الأمر الذي يبدو منطقيًا. ولكن منذ ذلك الحين ، مرت العديد من السنوات وتغيرت متطلبات الحزم وتجميعها قليلاً.

نسخ لصق هو الشر ، وإن لم يكن دائما


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

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

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

وأي واحد؟


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

public function __construct( $dsn, $username = '', $password = '', $options = [], $driverOptions= null ); 

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

المشكلة الثالثة هي مشكلة توصيل xPDO بالمشروع. لقد تبدى برنامج Composer فورًا في الاعتبار ، لكن الإصدار 2.x الذي يعمل عليه MODX الحالي لا يدعم Composer ، ويستخدم الفرع 3.x مساحات الأسماء وأسماء الفئات مكتوبة بشكل مختلف عن 2.x ، مما يؤدي إلى تعارضات وأخطاء. بشكل عام ، غير متوافق. ثم اضطررت إلى استخدام أدوات git وتوصيل xPDO كوحدة فرعية.

كيفية استخدام وحدات فرعية



أولاً ، اقرأ الوثائق عليها.

إذا كان هذا مشروعًا جديدًا ، فأنت بحاجة إلى إضافة نموذج فرعي:

 $ git submodule add https://github.com/username/reponame 

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

بحيث يمكن لمطور آخر استنساخ المشروع بكل التبعيات ، فأنت بحاجة إلى إنشاء تكوين .gitmodules لوحدات فرعية. في مشروع Slackify ، يشبه هذا:

 [submodule "_build/xpdo"] path = _build/xpdo url = https://github.com/modxcms/xpdo.git branch = 2.x 

بعد ذلك ، عند الاستنساخ ، حدد فقط العلامة العودية وسوف تقوم git بتنزيل جميع المستودعات التابعة.
نتيجة لذلك ، لدينا xPDO ، يمكن استخدام xPDO دون الاتصال بقاعدة البيانات ، إذا لم يكن ذلك ضروريًا ، يمكن توصيل xPDO برمز المكون باعتباره تبعية خارجية (git subodule). الآن تنفيذ البرنامج النصي البناء.

دعنا نفهم


سوف أصف البرنامج النصي للبناء الخاص بـ Slackify add- on الذي نشرته مؤخرًا. هذا المكون مجاني ومتاح للجمهور على GitHub ، مما سيسهل الدراسة الذاتية.

ربط xPDO


نحذف مهمة الثوابت مع اسم الحزمة والمكالمات الضرورية الأخرى وتوصيل xPDO.

 require_once 'xpdo/xpdo/xpdo.class.php'; require_once 'xpdo/xpdo/transport/xpdotransport.class.php'; $xpdo = xPDO::getInstance('db', [ xPDO::OPT_CACHE_PATH => __DIR__ . '/../cache/', xPDO::OPT_HYDRATE_FIELDS => true, xPDO::OPT_HYDRATE_RELATED_OBJECTS => true, xPDO::OPT_HYDRATE_ADHOC_FIELDS => true, xPDO::OPT_CONNECTIONS => [ [ 'dsn' => 'mysql:host=localhost;dbname=xpdotest;charset=utf8', 'username' => 'test', 'password' => 'test', 'options' => [xPDO::OPT_CONN_MUTABLE => true], 'driverOptions' => [], ] ] ]); 

أضفت الوحدة الفرعية xPDO إلى المجلد _build ، والذي نحتاجه فقط في مرحلة تطوير وتجميع الحزمة والتي لا تدخل في الأرشيف الرئيسي للمكون. النسخة الثانية من xPDO على الموقع مع MODX مباشر لسنا بحاجة.

في إعدادات اتصال xPDO ، قمت بتعيين اسم قاعدة البيانات في dsn ، لكنه لا يلعب أي دور. من المهم أن مجلد ذاكرة التخزين المؤقت داخل xPDO قابل للكتابة. هذا كل شيء ، تتم تهيئة xPDO.

جعل الاختراق صعبة مع الطبقات


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

 class modNamespace extends xPDOObject {} class modSystemSetting extends xPDOObject {} 

نخلق فئة وهمية (كعب) ، وهو أمر ضروري لإنشاء الكائن المطلوب. لن يلزم القيام بذلك إذا لم يتحقق xPDO بالتحديد من الفئة التي ينتمي إليها الكائن. لكنه يتحقق.

ولكن هناك حالات خاصة عندما تحتاج إلى القيام بأكثر من مجرد تحديد فئة. هذه هي حالات التبعية بين الطبقات. على سبيل المثال ، نحتاج إلى إضافة مكون إضافي إلى الفئة. في الكود ، فقط $category->addOne($plugin); ولكن في حالتنا هذا لن ينجح.

إذا نظرت إلى مخطط قاعدة بيانات MODX ، فربما رأيت عناصر مثل التجميعية والمركبة. يتم كتابتها عنهم في الوثائق ، ولكن إذا كان بطريقة بسيطة ، فإنها تصف العلاقة بين الطبقات.

في حالتنا ، يمكن أن يكون هناك العديد من المكونات الإضافية في فئة ، يكون العنصر التجميعي مسؤولًا عنها في فئة modCategory . لذلك ، نظرًا لوجود فصل بدون تنفيذ ملموس ، نحتاج إلى الإشارة إلى هذا الاتصال يدويًا. من الأسهل القيام بذلك عن طريق getFKDefinition أسلوب getFKDefinition :

 class modCategory extends xPDOObject { public function getFKDefinition($alias) { $aggregates = [ 'Plugins' => [ 'class' => 'modPlugin', 'local' => 'id', 'foreign' => 'category', 'cardinality' => 'many', 'owner' => 'local', ] ]; return isset($aggregates[$alias]) ? $aggregates[$alias] : []; } } 

في مكوننا ، يتم استخدام المكونات الإضافية فقط ، لذلك نضيف روابط لها فقط. بعد ذلك ، يمكن بسهولة إضافة طريقة addMany للفئة modCategory المكونات الإضافية الضرورية للفئة ، ثم إلى الحزمة.

إنشاء حزمة


 $package = new xPDOTransport($xpdo, $signature, $directory); 

كما ترون ، كل شيء بسيط للغاية. نحن هنا نحتاج إلى تمرير المعلمة $xpdo ، والتي قمنا $xpdo في البداية. إن لم يكن لهذه اللحظة ، لن تكون هناك مشكلة 2. $signature - اسم الحزمة ، بما في ذلك الإصدار ، $directory - المكان الذي سيتم وضع الحزمة فيه بعناية. من أين تأتي هذه المتغيرات ، انظر لنفسك في المصدر.

قم بإنشاء مساحة اسم وإضافتها إلى الحزمة


نحتاج إلى مساحة اسم من أجل ربط المعجم وإعدادات النظام بها. في حالتنا ، فقط لهذا ، لم يتم النظر في الآخرين.

 $namespace = new modNamespace($xpdo); $namespace->fromArray([ 'id' => PKG_NAME_LOWER, 'name' => PKG_NAME_LOWER, 'path' => '{core_path}components/' . PKG_NAME_LOWER . '/', ]); $package->put($namespace, [ xPDOTransport::UNIQUE_KEY => 'name', xPDOTransport::PRESERVE_KEYS => true, xPDOTransport::UPDATE_OBJECT => true, xPDOTransport::RESOLVE_FILES => true, xPDOTransport::RESOLVE_PHP => true, xPDOTransport::NATIVE_KEY => PKG_NAME_LOWER, 'namespace' => PKG_NAME_LOWER, 'package' => 'modx', 'resolve' => null, 'validate' => null ]); 

الجزء الأول واضح لأي شخص كتب كود MODX على الإطلاق. والثاني ، مع إضافة الحزمة ، هو أكثر تعقيدًا بقليل. تأخذ طريقة put معلمتين: الكائن نفسه ومجموعة من المعلمات التي تصف هذا الكائن وسلوكه المحتمل في وقت تثبيت الحزمة. على سبيل المثال ، xPDOTransport::UNIQUE_KEY => 'name' أن حقل الاسم الذي يحمل اسم مساحة الاسم نفسه كقيمة سيتم استخدامه لمساحة الاسم كمفتاح فريد في قاعدة البيانات. يمكنك قراءة المزيد حول المعلمات في وثائق xPDO ، وأفضل من خلال دراسة التعليمات البرمجية المصدر.

بنفس الطريقة ، يمكنك إضافة كائنات أخرى ، مثل إعدادات النظام.

 $package->put($setting, [ xPDOTransport::UNIQUE_KEY => 'key', xPDOTransport::PRESERVE_KEYS => true, xPDOTransport::UPDATE_OBJECT => true, 'class' => 'modSystemSetting', 'resolve' => null, 'validate' => null, 'package' => 'modx', ]); 

إنشاء فئة


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

 $package->put($category, [ xPDOTransport::UNIQUE_KEY => 'category', xPDOTransport::PRESERVE_KEYS => false, xPDOTransport::UPDATE_OBJECT => true, xPDOTransport::ABORT_INSTALL_ON_VEHICLE_FAIL => true, xPDOTransport::RELATED_OBJECTS => true, xPDOTransport::RELATED_OBJECT_ATTRIBUTES => [ 'Plugins' => [ xPDOTransport::UNIQUE_KEY => 'name', xPDOTransport::PRESERVE_KEYS => false, xPDOTransport::UPDATE_OBJECT => false, xPDOTransport::RELATED_OBJECTS => true ], 'PluginEvents' => [ xPDOTransport::UNIQUE_KEY => ['pluginid', 'event'], xPDOTransport::PRESERVE_KEYS => true, xPDOTransport::UPDATE_OBJECT => false, xPDOTransport::RELATED_OBJECTS => true ] ], xPDOTransport::NATIVE_KEY => true, 'package' => 'modx', 'validate' => $validators, 'resolve' => $resolvers ]); 

يبدو بشع ، ولكن لم ير ذلك. المعلمة الهامة هي xPDOTransport::RELATED_OBJECTS => true ، مما يشير إلى أن الفئة تحتوي على عناصر متداخلة تحتاج أيضًا إلى تعبئتها ثم تثبيتها.

نظرًا لأن معظم الوحدات تحتوي على عناصر مختلفة (قطع ، مقتطفات ، مكونات إضافية) ، فإن الفئة ذات العناصر هي أهم قطعة في حزمة النقل. لذلك ، من هنا يتم تحديد أجهزة التحقق من الصحة والمحولات ، والتي يتم تنفيذها أثناء تثبيت الحزمة.
يتم إجراء مصادقة قبل التثبيت ، محللات - بعد.

لقد نسيت تقريبا ، قبل تعبئة الفئة ، نحتاج إلى إضافة عناصرنا إليها. مثل هذا:

 $plugins = include $sources['data'] . 'transport.plugins.php'; if (is_array($plugins)) { $category->addMany($plugins, 'Plugins'); } 

إضافة بيانات أخرى إلى الحزمة.


في الحزمة ، تحتاج إلى إضافة ملف آخر بترخيص وملف به سجل تغيير وملف مع وصف للمكون. إذا لزم الأمر ، يمكنك إضافة برنامج نصي خاص آخر من خلال سمة setup-options ، والتي ستظهر لك النافذة قبل تثبيت الحزمة. هذا هو عندما بدلا من "تثبيت" الزر "خيارات التثبيت". ومن الإصدار MODX 2.4 ، أصبح من الممكن تحديد التبعيات بين الحزم باستخدام السمة require ، وفيه يمكنك أيضًا تحديد إصدار PHP و MODX.

 $package->setAttribute('changelog', file_get_contents($sources['docs'] . 'changelog.txt')); $package->setAttribute('license', file_get_contents($sources['docs'] . 'license.txt')); $package->setAttribute('readme', file_get_contents($sources['docs'] . 'readme.txt')); $package->setAttribute('requires', ['php' => '>=5.4']); $package->setAttribute('setup-options', ['source' => $sources['build'] . 'setup.options.php']); 

نحن حزمة


 if ($package->pack()) { $xpdo->log(xPDO::LOG_LEVEL_INFO, "Package built"); } 

هذا كل شيء ، والتقاط الحزمة النهائية في حزم _packages ، حسنا ، أو من حيث قمت بتكوين التجميع.

ما هي النتيجة؟


تجاوزت النتيجة توقعاتي ، نظرًا لأن هذا النهج ، رغم أنه يفرض بعض القيود وفي بعض الأماكن يضيف بعض الإزعاج ، لكنه يفوز من حيث إمكانيات التطبيق.

لإنشاء الحزمة ، فقط قم بتنفيذ أمرين:

 git clone --recursive git@github.com:Alroniks/modx-slackify.git cd modx-slackify/_build && php build.transport.php 

الأول هو استنساخ المستودع ووحداته الفرعية. المعلمة الهامة هي - --recursive ، بفضل git سيتم تنزيلها وتثبيتها ، بالإضافة إلى رمز المكون نفسه ، جميع التبعيات الموصوفة على أنها وحدات فرعية.

والثاني هو بناء الحزمة مباشرة. بعد ذلك ، يمكنك التقاط package-1.0.0-pl.transport.zip النهائية _packages مجلد _packages وتحميلها ، على سبيل المثال ، إلى المستودع.

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

طرح الأسئلة ، حاول الإجابة.

ملاحظة: لا تمر ، ضع نجمة سلاكيفي على جيثب ، من فضلك.

Source: https://habr.com/ru/post/ar439420/


All Articles