PHP 8.2: ما الجديد؟
الإصدار الجديد من PHP على الأبواب. ما هي التطبيقات الجديدة التي يجب أن تعرفها؟ راجع هذه المقالة لمعرفة ذلك!
اقرأ الجزء الأول من سلسلة PHP المخصصة لاتصالات الخدمات المصغرة في إطار عمل Symfony والطريقة الأكثر شيوعًا - اتصال AMQP باستخدام RabbitMQ.
أجبرت بنية التطبيقات الحديثة المطورين على تغيير طريقة التفكير في التواصل بين المكونات المختلفة لأنظمة تكنولوجيا المعلومات. في السابق كان الأمر أبسط من ذلك - تم إنشاء معظم الأنظمة كهياكل متجانسة مترابطة مع بعضها البعض من خلال شبكة من الاتصالات المنطقية للأعمال. الحفاظ على مثل هذه التبعيات في PHP المشروع كان تحديًا كبيرًا بالنسبة لـ مطورو PHPوالشعبية المتزايدة لحلول SaaS والزيادة الهائلة في شعبية حلول SaaS، والزيادة الكبيرة في شعبية السحابة تسببت الخدمات في أننا نسمع اليوم أكثر فأكثر عن الخدمات المصغرة ونمطية التطبيقات.
كيف يمكننا، من خلال إنشاء خدمات مصغرة مستقلة، أن نجعلها تتبادل المعلومات مع بعضها البعض؟
هذه المقالة هي الأولى في سلسلة من المنشورات عن اتصالات الخدمات المصغرة في سيمفوني إطار العمل ويغطي الطريقة الأكثر شيوعًا - اتصال AMQP باستخدام RabbitMQ.
إنشاء تطبيقين مستقلين وتحقيق الاتصال بينهما باستخدام ناقل الرسائل فقط.
لدينا تطبيقان وهميان ومستقلان ومستقلان:
* التطبيق1
:: التي ترسل إشعارات بالبريد الإلكتروني والرسائل النصية القصيرة إلى الموظفين
* التطبيق2
:: مما يتيح لك إدارة عمل الموظفين وتعيين المهام لهم.
نريد إنشاء نظام حديث وبسيط يتم بموجبه إسناد العمل إلى موظف في التطبيق2
سيرسل إشعارًا إلى العميل باستخدام التطبيق1
. على الرغم من المظاهر، فإن الأمر بسيط للغاية!
لغرض هذه المقالة، سنستخدم أحدث إصدار من سيمفوني (الإصدار 6.1 وقت كتابة هذا المقال) وأحدث إصدار من PHP (8.1). في بضع خطوات بسيطة للغاية سننشئ بيئة Docker محلية عاملة مع اثنين من الخدمات المصغرة. كل ما تحتاجه هو
* جهاز كمبيوتر يعمل,
* تثبيت Docker + بيئة تركيب Docker Compose
* وتكوينه محليًا سيمفوني CLI وبعض وقت الفراغ
سنستخدم إمكانيات Docker كأداة للمحاكاة الافتراضية للتطبيقات والحاويات. دعونا نبدأ بإنشاء شجرة دليل، وهو إطار عمل لـ تطبيقات سيمفوني، ووصف البنية التحتية لبيئاتنا باستخدام docker-compose.yml
الملف.
قرص مضغوط ~
mkdir microservices-in-symfony
cd microservices-in-symfony
تطبيق سيمفوني جديد1
تطبيق سيمفوني جديد2
المس docker-compose.yml docker-compose.yml
لقد أنشأنا دليلين لتطبيقين منفصلين من تطبيقات Symfony وأنشأنا دليلين فارغين docker-compose.yml
لبدء تشغيل بيئتنا.
دعونا نضيف الأقسام التالية إلى docker-compose.yml
file:
الإصدار: '3.8'
الخدمات:
التطبيق 1:
اسم الحاوية: app1
البناء: app1/.
إعادة التشغيل: عند الفشل
envfile: app1/.env
البيئة:
اسم التطبيق: app1
تيتي: صحيح
stdinopen: صحيح
التطبيق2:
اسم الحاوية: app2
بناء: التطبيق2/.
إعادة التشغيل: عند الفشل
ملف envfile: app2/.env
البيئة:
اسم التطبيق: app2
تيتي: صحيح
stdinopen: صحيح
rabbitmq:
احتواء الاسم: rabbitmq
الصورة: rabbitmq: إدارة
المنافذ
- 15672:15672
- 5672:5672
البيئة:
- RABBITMQDEFAULTUSER=المستخدم
- RABBITMQDEFAULT_PASS=كلمة المرور
المصدر الكود متاح مباشرة: thecodest-co/microservices-in-symfony/blob/main/docker-compose.yml
لكن انتظر، ماذا حدث هنا؟ بالنسبة لأولئك غير المعتادين على Docker، قد يبدو ملف التكوين أعلاه غامضًا، ولكن الغرض منه بسيط للغاية. باستخدام Docker Compose نحن نبني ثلاث "خدمات":
للتشغيل السليم، ما زلنا بحاجة إلى ملف إرساء
الملفات التي هي مصدر بناء الصور. لذا دعونا ننشئها:
المس التطبيق1/ملف الإرساء
المس التطبيق2/ملف الإرساء
يحتوي كلا الملفين على نفس البنية بالضبط ويبدوان كما يلي:
من php:8.1
نسخ - من=composer:latest /usr/bin/composer /usr/local/bin/composer
نسخ . /التطبيق/
WORKDIR /التطبيق/
إضافة https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/lusr/local/bin/
قم بتشغيل chmod +x /usr/local/bin/in/stall-php-extensions &&&مزامنة &&
install-php-extensions amqp
تشغيل apt-get update
&&Apt-get install -y libzip-dev wget -no-install-recommends
&&أبت-get clean
&&& rm -rf -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
قم بتشغيل docker-php-ext-install zip;
CMD bash -c "cd /app && Composer install && php -a"
الكود المصدري متاح مباشرة: /thecodest-co/microservices-in-symfony/blob/main/app1/Dockerfile
يتم استخدام الملف أعلاه من قبل Docker Compose لبناء حاوية من صورة PHP 8.1 مع تثبيت Composer وامتداد AMQP. بالإضافة إلى ذلك، فإنه يقوم بتشغيل PHP intepreter في وضع الإلحاق للحفاظ على تشغيل الحاوية في الخلفية.
يجب أن يبدو الدليل وشجرة الملفات الآن كما يلي:
.
「التطبيق 1
│علمي ─ ملف الإرساء
| (...) # هيكل تطبيق سيمفوني
̄ ̄التطبيق2
| ملف الإرساء | ملف الإرساء
| (...) # هيكل تطبيق سيمفوني
│تعريف ─ docker-compose.yml
لنبدأ بـ التطبيق1
الدليل والتطبيق الأول.
في مثالنا، هو تطبيق يستمع ويستهلك الرسائل من قائمة الانتظار المرسلة من التطبيق2
كما هو موضح في المتطلبات:
تعيين وظيفة لعامل في
التطبيق2
سيرسل إشعارًا إلى العميل
لنبدأ بإضافة المكتبات المطلوبة. AMQP مدعومة أصلاً لـ سيمفوني/مسنجر
التمديد. سنقوم أيضًا بتثبيت مونولوج/مناجاة/مناجاة
لتتبع سجلات النظام لتسهيل تحليل سلوك التطبيق.
cd app1/
symfony composer composer reqqp amqp ampq-messenger monolog
بعد التثبيت، تمت إضافة ملف إضافي ضمن التكوين/الحزم/مسنجر.yaml
. وهو ملف تهيئة لمكون Symfony Messenger ولا نحتاج إلى التكوين الكامل.
استبدله بملف YAML أدناه:
إطار العمل:
رسول:
# قم بإلغاء ربط هذا (والنقل الفاشل أدناه) لإرسال الرسائل الفاشلة إلى هذا النقل للتعامل معها لاحقًا.
# فشل_النقل: فشل
النقل:
# https://symfony.com/doc/current/messenger.html#transport-configuration
الرسائل_الخارجية:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
خيارات:
الإعداد التلقائي: خطأ
تبادل:
الاسم: الرسائل
النوع: مباشر
مفتاح_النشر_التوجيه_الافتراضي: من_خارجي
قوائم الانتظار:
الرسائل:
مفاتيح الربط: [من_خارجي]
الكود المصدري متاح مباشرة: thecodest-co/microservices-in-symfony/blob/main/app1/config/packages/messenger.yaml
يستخدم Symfony Messenger للتواصل المتزامن وغير المتزامن في تطبيقات Symfony. وهو يدعم مجموعة متنوعة من وسائل النقلأو مصادر حقيقة طبقة النقل. في مثالنا، نستخدم امتداد AMQP الذي يدعم نظام طابور انتظار الأحداث RabbitMQ.
يُعرّف التكوين أعلاه وسيلة نقل جديدة باسم الرسائل_الخارجية
الذي يشير إلى ماسنجر_ترانسبورت_دسن
متغير البيئة ويحدد الاستماع المباشر على الرسائل
قناة في ناقل الرسائل. في هذه المرحلة، قم أيضًا بتحرير التطبيق1/.env
ملف وإضافة عنوان النقل المناسب.
“`env
(…)
MESSENGERTRANSPORTDSN=amqp://user:password@rabbitmq:5672/%2f/messages
(…)
“
After preparing the application framework and configuring the libraries, it is time to implement the business logic. We know that our application must respond to the assignment of a job to a worker. We also know that assigning a job in theapp2system changes the status of the job. So let's create a model that mimics the status change and save it in theapp1/Message/StatusUpdate.php` path:
{
الدالة العامة __construct(سلسلة محمية $status){} {}
دالة عامة getStatus(): سلسلة
{
إرجاع $this->status;
}
}
الكود المصدري متاح مباشرة: /thecodest-co/microservices-in-symfony/blob/main/app1/apprc/Message/StatusUpdate.php
ما زلنا بحاجة إلى فئة ستنفذ منطق العمل عندما تتلقى خدمتنا المصغرة الحدث أعلاه من قائمة الانتظار. لذا دعنا ننشئ فئة معالج الرسائل في app1/Handler/StatusUpdateHandler.php
المسار:
استخدام PsrLogLogLoggerInterface;
استخدم SymfonyComponentComponentMessengerAttributeAsMessageHandler;
[معالج الرسائل]
صنف StatusUpdateHandler
{
دالة عامة __إنشاء(
LoggerInterface المحمي $logger,
) {}
الدالة العامة __invoke(StatusUpdate $statusUpdate): باطل
{
$statusDescription = $statusUpdate->getStatus();
$this-> مدون-> تحذير('APP1: {STATUS_UPDATE} - '.$statusDescription);
// بقية منطق العمل، أي إرسال البريد الإلكتروني إلى المستخدم
// $This->>emailService->email()
}
}
الكود المصدري متاح مباشرة: /thecodest-co/microservices-in-symfony/blob/main/app1/apprc/Handler/StatusUpdateHandler.php
PHP تجعل السمات الأمور أسهل بكثير وتعني أنه في هذه الحالة بالذات لا داعي للقلق بشأن الأسلاك التلقائية أو إعلان الخدمة. خدمتنا المصغرة للتعامل مع أحداث المجال جاهزة، حان الوقت للانتقال إلى التطبيق الثاني.
سنلقي نظرة على التطبيق2
والدليل الثاني تطبيق سيمفوني. تتمثل فكرتنا في إرسال رسالة إلى قائمة الانتظار عندما يتم تعيين عامل مهمة في النظام. لذا دعنا نقوم بتهيئة سريعة لـ AMQP ونجعل خدمتنا المصغرة الثانية تبدأ في النشر تحديث الحالة
الأحداث إلى ناقل الرسائل.
تثبيت المكتبات هو نفسه تماماً كما في التطبيق الأول.
قرص مضغوط ...
cd app2/
symfony composer composer reqqp amqp ampq-messenger monolog
دعونا نتأكد من أن التطبيق2/.env
يحتوي الملف على إدخال DSN صالح ل RabbitMQ:
(...)
MESSENGER_TRANSPORT_DSN=amqp://user:password@rabbitmq:5672/%2f/messages
(...)
كل ما تبقى هو تكوين سيمفوني ماسنجر في التطبيق2/config/packages/messenger.yaml
file:
إطار العمل:
رسول:
# قم بإلغاء تحديد هذا (والنقل الفاشل أدناه) لإرسال الرسائل الفاشلة إلى هذا النقل للتعامل معها لاحقًا.
# فشل_النقل: فشل
النقل:
# https://symfony.com/doc/current/messenger.html#transport-configuration
غير متزامن
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
توجيه
# توجيه الرسائل إلى وسائل النقل
'AppMessageStatusStatusUpdate': غير متزامن
كما ترى، يشير تعريف النقل هذه المرة مباشرةً إلى غير متزامن
ويحدد التوجيه في شكل إرسال تحديث الحالة
رسالة إلى شبكة DSN المكوّنة. هذا هو المجال الوحيد للتكوين، كل ما تبقى هو إنشاء المنطق وطبقة التنفيذ لقائمة انتظار AMQP. لهذا سننشئ التوأم معالج تحديث الحالة StatusUpdateHandler
و تحديث الحالة
الفصول الدراسية في التطبيق2
.
استخدام PsrLogLogLoggerInterface;
استخدم SymfonyComponentComponentMessengerAttributeAsMessageHandler;
[معالج الرسائل]
صنف StatusUpdateHandler
{
دالة عامة __إنشاء(
خاص للقراءة فقط LoggerInterface $logger,
) {}
الدالة العمومية __invoke(StatusUpdate $statusUpdate): باطل
{
$statusDescription = $statusUpdate->getStatus();
$this->مدون-> تحذير('APP2: {STATUS_UPDATE} - '.$statusDescription);
## منطق العمل، أي إرسال إشعار داخلي أو وضع بعض الأنظمة الأخرى في قائمة الانتظار
}
}
{
الدالة العامة __construct(سلسلة محمية $status){} {}
دالة عامة getStatus(): سلسلة
{
إرجاع $this->status;
}
}
الكود المصدري متاح مباشرة: /thecodest-co/microservices-in-symfony/blob/main/app2/apprc/Message/StatusUpdate.php
أخيرًا، كل ما يجب القيام به هو إنشاء طريقة لإرسال رسالة إلى ناقل الرسائل. سنقوم بإنشاء أمر سيمفوني لهذا
استخدام SymfonyComponentConsoleConsoleAttributeAsCommand;
استخدام SymfonyComponentConsoleCommandCommandCommand;
استخدام SymfonyComponentComponentConsoleConsoleInputInputInterface;
استخدم SymfonyComponentConsoleConsoleConputOutputOutputInterface؛
استخدام SymfonyComponentComponentMessengerMessageBusBusInterface;
[كأمر(
الاسم: "التطبيق: إرسال"
)]
صنف SendStatusCommand يمتد الأمر
{
إنشاء دالة عامة (خاص للقراءة فقط MessageBusInterface $messageBus، سلسلة $name = لاغية)
{
الأصل::إنشاء($name);
}
الدالة المحمية execute(InputInterface $input، OutputInterface $output): int
{
$status = "تم تعيين العامل X إلى Y";
$is-> ناقل الرسائل->dispatch(
الرسالة: جديد StatusUpdate($status)
);
إرجاع الأمر::نجاح;
}
}
شكرًا لـ حقن التبعية يمكننا استخدام مثيل ل واجهة ناقل الرسائل
في قيادتنا وإرسال تحديث الحالة
رسالة عبر إرسال()
إلى قائمة الانتظار الخاصة بنا. بالإضافة إلى ذلك، نستخدم هنا أيضًا سمات PHP.
هذا كل شيء - كل ما تبقى هو تشغيل بيئة Docker Compose ونرى كيف تتصرف تطبيقاتنا.
باستخدام Docker Compose، سيتم إنشاء الحاويات التي تحتوي على تطبيقينا وتشغيلها كمثيلين منفصلين، وستكون الطبقة الوسيطة الوحيدة هي أرنبمك
الحاوية وتنفيذ ناقل الرسائل الخاص بنا.
من الدليل الجذر للمشروع، لنقم بتشغيل الأوامر التالية:
<cd ../ # تأكد من أنك في الدليل الرئيسي
docker-compose up --build -d
يمكن أن يستغرق هذا الأمر بعض الوقت، حيث أنه يبني حاويتين منفصلتين مع PHP 8.1 + AMQP ويسحب صورة RabbitMQ. كن صبورًا. بعد بناء الصور يمكنك إطلاق الأمر من التطبيق2
وإرسال بعض الرسائل في قائمة انتظار.
docker exec -it app2 php bin/console app/console app:send
يمكنك القيام بذلك بقدر ما تستطيع. طالما لا يوجد المستهلك لن تتم معالجة رسائلك. بمجرد أن تقوم بتشغيل التطبيق1
واستهلك جميع الرسائل التي ستظهر على شاشتك.
docker exec -it app1 php bin/console messenger:consume -vv external_messages
الكامل كود المصدر إلى جانب ملف README في مستودعنا العام The Codest Github
تتيح Symfony بمكتباتها وأدواتها نهجًا سريعًا وفعالًا لتطوير تطبيقات الويب. مع بضعة أوامر وبضعة أسطر من التعليمات البرمجية يمكننا إنشاء نظام اتصال حديث بين التطبيقات. سيمفوني، مثل PHPمثالي لـ تطوير تطبيقات الويب وبفضل نظامه البيئي وسهولة تنفيذه، يحقق هذا النظام البيئي بعضًا من أفضل مؤشرات الوقت اللازم للوصول إلى السوق.
ومع ذلك، فإن السرعة لا تعني دائمًا أنها جيدة - في المثال أعلاه قدمنا أبسط وأسرع طريقة للاتصال. ما سيلاحظه أكثر الفضوليين بالتأكيد أن هناك نقصًا في فصل أحداث المجال خارج طبقة التطبيق - في الإصدار الحالي يتم تكرارها، ولا يوجد دعم كامل لـ المغلف
، من بين أمور أخرى لا يوجد طوابع بريدية
. بالنسبة لهؤلاء وغيرهم، أدعوكم لقراءة الجزء الثاني، حيث سنغطي موضوع توحيد بنية المجال لتطبيقات Symfony في بيئة الخدمات المصغرة، ومناقشة طريقة اتصال الخدمات المصغرة الشائعة الثانية - هذه المرة متزامنة، استنادًا إلى واجهة برمجة تطبيقات REST.