Skip to content

Latest commit

 

History

History
329 lines (256 loc) · 21.8 KB

facades.md

File metadata and controls

329 lines (256 loc) · 21.8 KB

Facades

مقدمة

خلال قراءتك لتوثيق لارافيل ستشاهد أمثلة لأكواد تقوم بالتفاعل مع ميزات لارافيل بواسطة "facades". توفر واجهات لارافيل Facades واجهة ستاتيكية (static interface) للكائنات (classes) المتوافرة في حاوي خدمات التطبيق. تحتوي لارافيل العديد من واجهات Facades التي توفر الوصول لمعظم ميزات لارافيل.

تعمل واجهات لارافيل Facades بصفتها وكيل ستاتيكي ("static proxies") للكائنات الأساسية في حاوي الخدمة، حيث توفر ميزة الصياغة المعبرة والموجزة مع الحفاظ على قابلية الاختبار ومرونة أكبر من الطرق الستاتيكية (static methods) التقليدية. من الطبيعي جداً عدم فهمك بشكل كامل لكيفية عمل Facades ضمنياً، عليك فقط بالمسايرة واكمال تعلمك عن لارافيل.

كل واجهات لارافيل Facades معرفة ضمن نطاق الأسماء Illuminate\Support\Facades. أي أنه يمكننا وبسهولة الوصول لـ Facades بالأسلوب التالي:

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;

Route::get('/cache', function () {
    return Cache::get('key');
});

خلال توثيق لارافيل يوجد العديد من الأمثلة التي تستعمل واجهات Facades لتوضيح ميزات متنوعة لإطار عمل لارافيل.

التوابع المساعدة (Helper Functions)

واستكمالاً لواجهات Facades تقدم لارافيل عدة توابع مساعدة متنوعة لتجعل التعامل مع الميزات العامة في لارافيل أكثر سهولة. قد تتعامل مع بعض التوابع المساعدة الشائعة مثل view، response، url، config وغيرها المزيد. كل تابع مساعد مقدم من لارافيل يتم توثيقه مع الميزة التي يقدمها، وبكل الأحوال تتوفر لائحة كاملة في التوثيق المخصص للتوابع المساعدة .

على سبيل المثال، بدلاً من استخدام الـ Facade التالي Illuminate\Support\Facades\Response لانشاء رد (response) من النوع JSON يمكنك ببساطة استخدام التابع المساعد response. ولأن التوابع المساعدة متوفرة على نطاق التطبيق (globally available)، لست بحاجة لاستيراد (import) أي صفوف لاستخدمها:

use Illuminate\Support\Facades\Response;

Route::get('/users', function () {
    return Response::json([
        // ...
    ]);
});

Route::get('/users', function () {
    return response()->json([
        // ...
    ]);
});

متى تُستخدم واجهات Facades

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

بكل الأحوال، يجب الاحتياط قليلاً عند استعمال واجهات Facades. لأن خطرها الرئيسي يكمن بتمدد نطاق الكائن ("scope creep"). بما أن واجهات Facades سهلة الاستعمال ولا تحتاج لحقن، فمن السهولة أن تتضخم كائناتك (classes) عند استخدام أكثر من واجهة Facade في كائن واحد. إن استخدام حقن الاعتماديات من المحتمل أن يحد من المشكلة بسبب التحذيرات المرئية التي يصدرها الباني (constructor) الضخم بأن الكائن يتضخم بشكل كبير. فعند استخدامك لواجهات Facades يجب إعارة انتباه خاص لحجم الكائن لكي يبقى نطاق مسؤليته (scope of responsibility) ضيقاً. وفي حال تضخم الكائن كثيراً، قد تحتاج لتقسيمه لعدة كائنات أصغر.

مقارنة واجهات Facades مع حقن الاعتماديات

واحد من الفوائد الأساسية لحقن الاعتمادية هو امكانية تبديل استخدامات (implementations) الكائن الذي تم حقنه. مما يفيد أثناء الاختبار حيث يمكنك حقن غرض مُقلِّد (mock) أو نموذج القابل للاستبدال (stub) وتتحقق من استدعاء مختلف الطرق فيها.

عملياً، ليس من الممكن استخدام الأغراض المُقلِّدة (mock) أو النماذج القابلة للاستبدال (stubs) على طريقة ستاتيكية للكائن. ولكن ولأن واجهات Facades تستخدم الطرق الديناميكة لتوكيل طرق لاستدعاء الكائنات تم الحصول عليها بواسطة حاوي الخدمة، يمكننا في الواقع اختبار Facades كما يمكننا اختبار نسخة (instance) لكائن تم حقنه. على سبيل المثال ليكن لدينا المسار (route) التالي:

use Illuminate\Support\Facades\Cache;

Route::get('/cache', function () {
    return Cache::get('key');
});

باستخدام طرق الاختبار الخاصة بلارافيل Facade، يمكننا كتابة النص التالي للتحقق من أنه تم استدعاء الطريقة Cache::get بالوسيط الذي نتوقعه:

use Illuminate\Support\Facades\Cache;

/**
 * A basic functional test example.
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
}

مقارنة واجهات Facades بالتوابع المساعدة (Helper Functions)

بالإضافة لواجهات Facades تحتوي لارافيل العديد من التوابع المساعدة التي تقوم بالمهام الشائعة كإنشاء واجهات (views)، إطلاق الأحداث (events)، توزيع الأعمال، أو ارسال ردود (responses) من نوع HTTP. والعديد من هذه التوابع المساعدة يقوم بتنفيذ الوظيفة نفسها لواجهة Facade المقابلة لها، فعلى سبيل المثال استدعاء واجهة Facade التالي مطابق لاستدعاء التابع المساعد:

return Illuminate\Support\Facades\View::make('profile');

return view('profile');

عملياً لا يوجد أي فرق بين واجهات Facades والتوابع المساعدة. عند استخدام التوابع المساعدة، يمكنك اختبارها بنفس الأسلوب الذي قد تختبر فيه واجهة Facade الموافقة. على سبيل المثال ليكن لدينا المسار (route) التالي:

Route::get('/cache', function () {
    return cache('key');
});

ضمنياً يقوم لتابع المساعد cache باستدعاء الطريقة get على الكائن المضمن في واجهة Facade التالية Cache. مما يعني أنه حتى لو قمنا باستخدام التابع المساعد، يمكننا كتابة الاختبار التالي للتأكد من أنه تم استدعاء الطريقة بالوسيط الذي نتوقعه:

use Illuminate\Support\Facades\Cache;

/**
 * A basic functional test example.
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
            ->with('key')
            ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
}

كيفية عمل واجهات Facades

في تطبيق لارافيل، واجهة Facade هي كائن يوفر الوصول لكائن من حاوي الخدمات. حيث أن الآلية التي تسمح بذلك موجودة في الكائن Facade. إن واجهات لارافيل Facades وأي واجهات Facades تقوم بإنشائها، سوف ترث من الكائن الأساسي (base class) Illuminate\Support\Facades\Facade.

الكائن الأساسي Facade يستخدم الطريقة الجاهزة (magic-method) ()callStatic__ لتحويل الاستدعاءات من واجهة Facade لكائن يتم الحصول عليه من حاوي الخدمات. في المثال التالي، سيتم استدعاء نظام الذاكرة المؤقت (cache system) الخاص بلارافيل. عند القاء نظرة على هذا الكود قد تظن بأن الطريقة الستاتيكية get يتم استدعائها على الصف Cache:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}

لاحظ في أعلى الملف بأننا نقوم باستيراد (importing) واجهة Facade التالية Cache. حيث تقوم واجهة Facade بالعمل كوكيل للوصول للاستخدام (implementation) الخاص بالواجهة Illuminate\Contracts\Cache\Factory. حيث أن أي استدعاءات نقوم بها باستخدام واجهة Facade سيتم تمريرها للنسخة (instance) الضمنية في خدمة الذاكرة المؤقتة في لارافيل.

اذا قمنا بإلقاء نظرة على الكائن Illuminate\Support\Facades\Cache ستجد بأنه لا وجود للطريقة الستاتيكية get:

class Cache extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }
}

بدلاً من ذلك ترث واجهة Facade التالية Cache من الصف الأساسي Facade وتُعرِّف الطريقة ()getFacadeAccessor. إن مهمة هذه الطريقة هو إعادة اسم ارتباط خاص بحاوي الخدمات. عندما يشير المستخدم لأي طريقة ستاتيكية في واجهة Facade التالية Cache ستقوم لارافيل بالحصول على الارتباط بين cache و حاوي الخدمات وتنفيذ الطريقة المطلوبة (في هذه الحالة الطريقة get) على الكائن.

واجهات Facades أثناء التنفيذ

يمكنك معاملة أي كائن من كائناتك بالتطبيق كما لو كان واجهة Facades باستخدام واجهات Facades أثناء التنفيذ. لتوضيح كيفية استخدام ذلك، دعنا بدايةً نتصفح بعض الأكواد التي لا تستخدم واجهات Facades أثناء التنفيذ. على سبيل المثال لنفترض بأن النموذج (model) التالي Podcast يحتوي على طريقة publish. حسناً لكي نقوم بنشر بودكاست نحتاج لحقن نسخة (instance) من الناشر Publisher:

<?php

namespace App\Models;

use App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * Publish the podcast.
     *
     * @param  Publisher  $publisher
     * @return void
     */
    public function publish(Publisher $publisher)
    {
        $this->update(['publishing' => now()]);

        $publisher->publish($this);
    }
}

يسمح لنا حقن استخدام (implementation) للناشر publisher في الطريقة باختبار الطريقة على انفراد طالما أننا قادرون على تقليد (mock) الناشر الذي تم حقنه. بكل الأحوال مطلوب بشكل دائم تمرير نسخة (instance) من الناشر publisher في كل مرة نقوم فيها باستدعاء الطريقة publish. لذلك وباستخدام واجهات Facades أثناء التنفيذ يمكننا المحافظة على قابلية الاختبار بدون أن نكون مطالبين بشكل صريح بتمرير نسخة من Publisher. لإنشاء واجهة Facade أثناء التنفيذ أضف كلمة Facades كبادئة لنطاق الأسماء (namespace) للكائن المستورد (imported class):

<?php

namespace App\Models;

use Facades\App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
        * Publish the podcast.
        *
        * @return void
        */
    public function publish()
    {
        $this->update(['publishing' => now()]);

        Publisher::publish($this);
    }
}

عند استخدام واجهات Facades أثناء التنفيذ سيتم الحصول على استخدام (implementation) للواجهة publisher من حاوي الخدمات باستخدام جزء من الواجهة أو اسم الكائن الذي يظهر بعد البادئة Facades. عند الاختبار يمكننا استخدام التوابع المساعدة للاختبار المُدمجة بلارافيل لتقليد (mock) استدعاء هذه الطريقة:

<?php

namespace Tests\Feature;

use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PodcastTest extends TestCase
{
    use RefreshDatabase;

    /**
     * A test example.
     *
     * @return void
     */
    public function test_podcast_can_be_published()
    {
        $podcast = Podcast::factory()->create();

        Publisher::shouldReceive('publish')->once()->with($podcast);

        $podcast->publish();
    }
}

مرجع لكائنات Facades

ستجد في الأسفل كل واجهات Facades وكائناتها الضمنية(underlying classes). يوفر هذا أداة سهلة للبحث عن أصل واجهة Facade في توثيق API الخاص بلارافيل. كما يتوفر مفتاح الارتباط الخاص بحاوي الخدمات في الأماكن المناسبة:

Facade Class Service Container Binding
App Illuminate\Foundation\Application app
Artisan Illuminate\Contracts\Console\Kernel artisan
Auth Illuminate\Auth\AuthManager auth
Auth (Instance) Illuminate\Contracts\Auth\Guard auth.driver
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Broadcast Illuminate\Contracts\Broadcasting\Factory  
Broadcast (Instance) Illuminate\Contracts\Broadcasting\Broadcaster  
Bus Illuminate\Contracts\Bus\Dispatcher  
Cache Illuminate\Cache\CacheManager cache
Cache (Instance) Illuminate\Cache\Repository cache.store
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
Crypt Illuminate\Encryption\Encrypter encrypter
Date Illuminate\Support\DateFactory date
DB Illuminate\Database\DatabaseManager db
DB (Instance) Illuminate\Database\Connection db.connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Gate Illuminate\Contracts\Auth\Access\Gate  
Hash Illuminate\Contracts\Hashing\Hasher hash
Http Illuminate\Http\Client\Factory  
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\LogManager log
Mail Illuminate\Mail\Mailer mailer
Notification Illuminate\Notifications\ChannelManager  
Password Illuminate\Auth\Passwords\PasswordBrokerManager auth.password
Password (Instance) Illuminate\Auth\Passwords\PasswordBroker auth.password.broker
Queue Illuminate\Queue\QueueManager queue
Queue (Instance) Illuminate\Contracts\Queue\Queue queue.connection
Queue (Base Class) Illuminate\Queue\Queue  
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\RedisManager redis
Redis (Instance) Illuminate\Redis\Connections\Connection redis.connection
Request Illuminate\Http\Request request
Response Illuminate\Contracts\Routing\ResponseFactory  
Response (Instance) Illuminate\Http\Response  
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Builder  
Session Illuminate\Session\SessionManager session
Session (Instance) Illuminate\Session\Store session.store
Storage Illuminate\Filesystem\FilesystemManager filesystem
Storage (Instance) Illuminate\Contracts\Filesystem\Filesystem filesystem.disk
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator (Instance) Illuminate\Validation\Validator  
View Illuminate\View\Factory view
View (Instance) Illuminate\View\View