أثناء العمل في مشروع Symfony مع فريقي، كنت بحاجة إلى إدخال مثيلات كائن قيمة محددة في إحدى خدماتي. القيم نفسها، في هذه الحالة بالذات، يجب تعيينها من القيم المتوفرة في ملف .env الخاص بنا.
يمكنني، بالطبع، تمرير قيم السلسلة مباشرة إلى خدمتي وجعل الخدمة تقوم بإنشاء مثيل لكائنات القيمة في المنشئ، لكنني أردت معرفة ما إذا كان من الممكن تكوينها في ملف Services.yaml وحقنها الكائنات التي تم إنشاء مثيل لها بالكامل بدلاً من ذلك. سيسمح لي هذا بتمرير مثيلات الكائنات هذه إلى خدمات متعددة ولن أضطر إلى تكرار إنشاء كائن القيمة داخل كل منها.
إليك كيف فعلت ذلك...
يستخدم تطبيقنا Twilio SDK. لدينا العديد من الخدمات التي تتضمن مكالمات SDK، وهي بحاجة إلى استخدام قيم التكوين الخاصة بالبيئة الخاصة بنا (مفتاح API الخاص بشركتنا لكل بيئة، وما إلى ذلك).
تستخدم Twilio API معرفات السلسلة أو SIDs. يحتوي كل نوع من SID على بادئة مختلفة مكونة من حرفين مرتبطة به، متبوعة بـ 32 حرفًا تتكون من الأرقام من 0 إلى 9 والأحرف من A إلى F (الأحرف الكبيرة والصغيرة).
على سبيل المثال:
أردت التأكد من صحة كائنات القيمة لكل نوع SID من أن القيمة التي تم تمريرها تحتوي على البادئة المناسبة لنوع SID هذا، بالإضافة إلى التأكد من أن السلسلة كانت بالطول الصحيح وأنها مكونة فقط من الأحرف المسموح بها .
يستخدم كل نوع من أنواع SID الخاصة بي نفس منطق ووظيفة التحقق من الصحة، مع التمييز فقط من خلال بادئة نوع SID، لذلك فمن المنطقي إنشاء سمة أساسية. يمكن أن يكون هذا فصلًا تجريديًا إذا كنت تفضل ذلك. لا أحتاج إلى مفهوم TwilioStringIdentifier في التطبيق كنوع معلمة أو أي شيء من هذا القبيل، لذلك أفضل السمة على فئة مجردة هنا.
تحدد هذه السمة طريقة مجردة getPrefixForSidType() التي يجب على كل نوع SID تنفيذها، مما يوفر البادئة المناسبة لهذا النوع المحدد. كما أنه ينفذ منطق التحقق من الصحة.
namespace App\Domain\Model\Twilio\Sid; use Assert\Assert; trait TwilioStringIdentifier { private readonly string $sid; abstract private function getPrefixForSidType(): string; public static function fromString(string $string): self { return new self($string); } public function __construct(string $sid) { Assert::that($sid) ->startsWith($this->getPrefixForSidType()) ->length(34) ->regex('/^[a-zA-Z]{2}[0-9a-fA-F]{32}$/') ; $this->sid = $sid; } public function asString(): string { return $this->sid; } }
تعتبر فئات كائنات القيمة التي تمثل كل نوع من أنواع SID بسيطة. يحتاجون فقط إلى استخدام سمة TwilioStringIdentifier وتحديد البادئة المناسبة عبر طريقة getPrefixForSidType().
namespace App\Domain\Model\Twilio\Sid; final readonly class AccountSid { use TwilioStringIdentifier; private function getPrefixForSidType(): string { return 'AC'; } }
فئات نوع SID الأخرى متطابقة باستثناء البادئة المحددة الخاصة بها.
نظرًا لأنه سيتم استخدام كائنات القيمة هذه في جميع أنحاء التطبيق ومع القيم المختلفة المرتبطة بها، وليس فقط القيم العالمية لشركتنا، فقد كنت بحاجة إلى طريقة لإدخال كائن من نوع معين في الخدمات والذي تم إنشاء مثيل له بالفعل بالقيم المحددة في ملف .env الخاص بنا
كنت أعلم أن Symfony لديه القدرة على تحديد الخدمات التي سيتم إنشاء مثيل لها عبر المصنع ولكنني لم أر أبدًا (على ما أذكر) أي شيء يتعلق بحقن كائن كان نتيجة لاستدعاء أسلوب من مكان آخر. كنت أعلم أيضًا أنه من الممكن أن يتم تمرير وسائط إلى أساليب المصنع هذه، ولم أكن متأكدًا من كيفية القيام بذلك باستخدام مثيل كائن قيمة واحد.
يسمح لك تعريف خدمة Symfony بتسمية كل خدمة. عادةً ما يتم ذلك باستخدام اسم فئة الخدمة:
App\Path\To\My\Service: class: App\Path\To\My\Service arguments: []
ولكن ليس من الضروري أن يتطابق اسم الخدمة مع اسم الفئة. يمكن أن يكون app.my_service أو Foo\Bar\Baz\Service أو أي شيء آخر.
إذن، ماذا لو قمت بإنشاء خدمة باسم فريد يمثل المثيل الذي تم إنشاء مثيل له لكائن القيمة الذي أحتاجه؟ يمكنني تمرير قيمة .env كوسيطة ومن ثم الحصول على مثيل الكائن هذا لإدخاله في فئات الخدمة الخاصة بي!
# Create services named with a Global "namespace" Global\Twilio\Sid\Account: factory: ['App\Domain\Model\Twilio\Sid\AccountSid', 'fromString'] arguments: ['%env(TWILIO_ACCOUNT_SID)%'] Global\Twilio\Sid\Api: factory: ['App\Domain\Model\Twilio\Sid\ApiSid', 'fromString'] arguments: ['%env(TWILIO_API_SID)%'] Global\Twilio\Sid\Application: factory: ['App\Domain\Model\Twilio\Sid\ApplicationSid', 'fromString'] arguments: ['%env(TWILIO_APP_SID)%']
ثم قم بتمرير هذه الخدمات (الكائنات) إلى خدمة Twilio الخاصة بي عبر الوسائط المسماة:
App\Service\Vendor\Twilio\TwilioService: arguments: $accountSid: '@Global\Twilio\Sid\Account' $apiSid: '@Global\Twilio\Sid\Api' $applicationSid: '@Global\Twilio\Sid\Application' $apiSecret: '%env(TWILIO_API_SECRET)%'
الآن يمكن لفئة الخدمة الخاصة بي أن تتوقع تلقي مثيلات كائن القيمة التي تم إنشاء مثيل لها بالكامل:
namespace App\Service\Vendor\Twilio; use App\Domain\Model\Twilio\Sid\AccountSid; use App\Domain\Model\Twilio\Sid\ApiSid; use App\Domain\Model\Twilio\Sid\ApplicationSid; final readonly class TwilioService { public function __construct( private AccountSid $accountSid, private ApiSid $apiSid, private ApplicationSid $applicationSid, private string $apiSecret ) {} }
فويلا!
Symfony مرن بدرجة كافية وبديهية بدرجة كافية بحيث كان من السهل معرفة كيفية القيام بذلك. نظرًا لأنني لم أتمكن من العثور على مرجع سريع للقيام بذلك في مكان آخر، اعتقدت أنني سأكتب هذا كمرجع لـ Future Me وأي شخص آخر قد يحتاج إلى القيام بشيء مماثل
تحياتي لك، وترميز سعيد!
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3