اكتشف إطار PHP Laravel


الدرس: حقن التبعية


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

المشكلة وحلها


المشكلة
لقد أخبرتك أن وحدة التحكم مسؤولة عن تلقي الطلبات وإرسال الردود. من الواضح أن هناك معالجات بين تنفيذهما ، يجب أن تكون الإجابة مبنية ، وأحيانًا تكون بسيطة جدًا ، وأحيانًا أطول ودقيقة. ولكن عموما لدينا لجهاز التحكم هذا العمل
framework Laravel MVC
تشغيل وحدة تحكم
خذ طريقة postForm من وحدة التحكم الخاصة بنا PhotoController  من الفصل السابق:

<?php
public function postForm(ImagesRequest $request)
{
    $image = $request->file('image');

    if($image->isValid())
    {
        $chemin = config('images.path');

        $extension = $image->getClientOriginalExtension();

        do {
            $nom = str_random(10) . '.' . $extension;
        } while(file_exists($chemin . '/' . $nom));

        if($image->move($chemin, $nom)) {
            return view('photo_ok');
        }
    }

    return redirect('photo')
        ->with('error','Désolé mais votre image ne peut pas être envoyée !');
}
ماذا لدينا للعلاج؟ نسترجع مراجع الصورة المرسلة ، ونستعيد مجلد الوجهة في الاعدادات ، ونجد امتدادا لملف الصورة ، وننشئ اسما وأخيرا نحفظ الصورة.
والسؤال هو: هل يجب أن تعرف وحدة التحكم كيف تتم هذه المعالجة؟ إذا كان لديك العديد من وحدات التحكم في التطبيق الخاص بك والتي يجب أن تؤدي نفس المعالجة ، فسيتضاعف هذا التطبيق. تخيل أنك ترغب بعد ذلك في تعديل تسجيل الصور ، على سبيل المثال عن طريق وضعها في قاعدة بيانات ، سوف تضطر إلى لمس كود جميع وحدات التحكم الخاصة بك! لا يعد تكرار الكود شيئًا جيدًا أبدًا ، بل قاعدة البرمجة السليمة هي أننا نبدأ في التساؤل حول تنظيم الكود بمجرد عمل نُسخ.
تعرف هذه التوصية باختصار DRY ("Don’t Repeat Yourself") و التي تعني ("لا تكرر نفسك" ) .
هناك عنصر آخر يجب أخذه في الاعتبار وهو اختبار الفئات. سنرى هذا الجانب المهم من البرمجة يتم تجاهله في كثير من الأحيان. لكي تكون الفئة قابلة للاختبار ، يجب أن تكون مهمته بسيطة ومحددة تمامًا ، ويجب ألا ترتبط ارتباطًا وثيقًا بفئة أخرى. هذا الاعتماد يجعل الاختبارات أكثر صعوبة.
الحل
إذن ما هو الحل؟ حقن التبعية!  دعونا نرى ما هو عليه. انظر إلى هذا المخطط:
framework Laravel MVC
حقن الإدارة
هناك فئة جديدة تلعب دورها في الإدارة ، فهي مسؤولة بالفعل عن المعالجة ، وحدة التحكم تستخدم أساليبها فقط. ولكن كيف يتم حقن هذه الفئة في وحدة التحكم؟ هنا هو كود وحدة التحكم مُعدل:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\ImagesRequest;
use App\Gestion\PhotoGestion;

class PhotoController extends Controller {

    public function getForm()
    {
        return view('photo');
    }

    public function postForm(
        ImagesRequest $request,
        PhotoGestion $photogestion)
    {

        if($photogestion->save($request->file('image'))) {
            return view('photo_ok');
        } 
        return redirect('photo')
            ->with('error','Désolé mais votre image ne peut pas être envoyée !');
    
    }

}
لاحظت أنه على مستوى الأسلوب postForm  هناك مُدخل من نوع جديد App\Gestion\PhotoGestion . نحن نستخدم طريقة save من الفئة  التي تم حقنها للقيام بالمعالجة.
وبهذه الطريقة تتجاهل وحدة التحكم تمامًا كيفية القيام بالإدارة ، فهي تعلم فقط أن الفصل PhotoGestion  يمكنه القيام بذلك. ويستخدم فقط طريقة هذه الفئة التي هي "محقونة" . الآن ربما تتساءل كيف يتم حقن هذه الفئة هناك ، وبعبارة أخرى كيف وأين يتم إنشاء هذا المثيل. حسنا Laravel ذكي بما فيه الكفاية للقيام بذلك بنفسه.
PHP متسامح للغاية من الأنواع المتغيرات. عندما تنشأ متغيرا فأنت لست مضطرًا لتحديد أنه سلسلة أو صفيف. PHP تخمين النوع وفقا للقيمة المعينة. وينطبق الشيء نفسه على المُدخلات في دالة. لكن لا أحد يمنعك من إعلان نوع كما فعلت هنا لمُدخل الدالة (لسوء الحظ في الوقت الحالي ، يتعرف PHP على المصفوفات والفئات). من الضروري أن يعرف Laravel الفئة الذي تهمه. نظرًا لأنني أعلن النوع ، فإن Laravel قادر على إنشاء مثيل من هذا النوع وحقنه في وحدة التحكم.
للعثور على فئة يستخدم Laravel الاستبطان (reflexion باللغة الإنجليزية) من PHP الذي يسمح لفحص الكود أثناء التنفيذ. كما يسمح لك بمعالجة التعليمات البرمجية وبالتالي إنشاء كائن لفئة معينة على سبيل المثال. يمكنك العثور على جميع المعلومات في دليل PHP  .

الإدارة


الآن وقد أخبرنا وحدة التحكم أن الفئة تهتم بالإدارة ، نحتاج إلى إنشائها. لتنظيم تطبيقنا بشكل صحيح ، نقوم بإنشاء مجلد جديد ووضع فئتنا فيه:
framework Laravel MVC
ملف الإدارة
التكويد ليس مشكلة لأنه مطابق لما كان لدينا في وحدة التحكم:

<?php

namespace App\Gestion;

class PhotoGestion
{

    public function save($image)
    {
        if($image->isValid())
        {
            $chemin = config('images.path');
            $extension = $image->getClientOriginalExtension();

            do {
                $nom = str_random(10) . '.' . $extension;
            } while(file_exists($chemin . '/' . $nom));

            return $image->move($chemin, $nom);
        }

        return false;
    }

}
احرص على عدم نسيان مساحات الأسماء!
الآن لدينا كود منظم تماما وسهل الصيانة والاختبار.
ولكن دعنا نذهب أبعد من ذلك قليلاً ، فلننشئ واجهة لفصلنا:
framework Laravel MVC
الواجهة لفئة PhotoGestion
مع هذا الكود:

<?php

namespace App\Gestion;

interface PhotoGestionInterface
{

  public function save($image);

}
ثم أبلغ فقط فئة PhotoGestion :

<?php
class PhotoGestion  implements PhotoGestionInterface
ما سيكون جيدًا الآن سيكون في وحدة التحكم الخاصة بنا للإشارة إلى الواجهة:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\ImagesRequest;
use App\Gestion\PhotoGestionInterface;

class PhotoController extends Controller
{

    public function getForm()
    {
        return view('photo');
    }

    public function postForm(
        ImagesRequest $request,
        PhotoGestionInterface $photogestion)
    {

        if($photogestion->save($request->file('image'))) {
            return view('photo_ok');
        } 
        return redirect('photo')
            ->with('error','Désolé mais votre image ne peut pas être envoyée !');
    
    }

}
القلق هو أن Laravel لا يمكنه تخمين الفئة من إنشاء هذه الواجهة:
framework Laravel MVC
لا يعرف Laravel كيفية إنشاء واجهة
كيف يمكننا تجاوزها ؟ 
عندما قدمت هيكل Laravel ذكرت وجود مقدمي الخدمات:
framework Laravel MVC
مقدمي الخدمات
فيما يصلح مقدمي الخدمات (provider)؟ بكل بساطة لتنفيذ التهيئة: الأحداث ، والوسيطة ، وقبل كل شيء روابط التبعية. Laravel لديه حاوية التبعية التي هي قلب عملها. بفضل هذه الحاوية سنتمكن من إنشاء رابط بين الواجهة والفئة.
افتح الملف app\Providers\AppServiceProvider.php  وأضف سطر التعليمات البرمجية هذا:

<?php
public function register()
{
    ...

    $this->app->bind(
        'App\Gestion\PhotoGestionInterface', 
        'App\Gestion\PhotoGestion'
    );
}
يتم تنشيط الطريقة Register  عند بدء تشغيل التطبيق ، وهو المكان المثالي للاتصال بنا. نحن هنا نقول للتطبيق ( app) إنشاء رابط ( bind) بين الواجهة App\Gestion\PhotoGestionInterface  والفئة App\Gestion\PhotoGestion . لذلك في كل مرة نشير فيها إلى هذه الواجهة في حقن Laravel سيعرف الفئة التي يجب إنشاء مثيل لها. إذا كنت ترغب في تغيير فئة الإدارة ، عليك فقط تعديل كود مقدم الخدمات provider .
الآن طلبنا يعمل  .
إذا تلقيت رسالة خطأ تخبرك أنه لا يمكن إنشاء مثيل للواجهة ، فأصدر الأمر:

php artisan clear-compiled

في الخلاصة


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