المسترجعات Accessors والمعدلات Mutators في Laravel


محمد أحمد العيل

المسترجِعات Accessors والمعدِّلات Mutators في Laravel هي مجموعة دوالّ مخصّصة يعرّفها المستخدم لتهيئة خواص النماذج Models. تُستخدم المسترجعات لتهيئة خواصّ النموذج عند طلب الحصول عليها من قاعدة البيانات، بينما تُستخدَم المعدّلات لتهيئة الخواصّ قبل حفظ النموذج في القاعدة.

تعريف مسترجع

تُسمى الدوال المسترجعة بالصيغة ()getFooAttribute حيث Foo هو اسم الخاصيّة التي نريد تهيئتها في الدالة، مع الانتباه إلى حالة الحرف الأول من الخاصية (حرف كبير Uppercase). سيستدعي Laravel تلقائيا هذه الدالة في كلّ مرة تبحث فيها عن قيمة الخاصيّة foo. لا يقتصر استخدام المسترجعات على سلاسل المحارف، بل يمكنك استخدامها لتهيئة أي نوع من البيانات تواريخ، أثمان، …إلخ.

سنفترض أن لدينا نموذجا باسم Member (عضو) يحوي الخاصيّات التاليّة:

first_name
last_name
email
password
last_visit
settings
created_at
updated_at

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

$user = App\Member::create([
    'first_name'  => 'mirza',
    'last_name'   => 'pasic',
    'email'       => 'mirza.pasic@bosnadev.com',
    'password'    => '!supersecretpassword!',
    'last_login'  => Carbon\Carbon::now(),
    'settings'    => ['two_factor_aut' => false, 'session_time' => 1200],
    'created_at'  => Carbon\Carbon::now(),
    'updated_at'  => Carbon\Carbon::now()
]);

يمكننا استخدام المسترجعات لتهيئة مُدخلات المستخدم:

use Illuminate\Database\Eloquent\Model;

/**
* Class Member
* @package App
*/
class Member extends Model
{
    /**
    * التأكد من تهيئة الاسم الشخصي بعد الحصول على النموذج من قاعدة البيانات
    * 
    * @param $value
    * @return string
    */
    public function getFirstNameAttribute($value)
    {
        return ucfirst($value);
    }

    /**
    * التأكد من تهيئة الاسم العائلي بعد الحصول على النموذج من قاعدة البيانات
    * 
    * @param $value
    * @return string
    */
    public function getLastNameAttribute($value)
    {
        return ucfirst($value);
    }
}

سيعمل المسترجعان getFirstNameAttribute و getLastNameAttribute على تهيئة الحقلين first_name (الاسم الشخصي) وlast_name (الاسم العائلي) على التوالي لجعل الحرف الأول في كلّ واحد منهما يُكتب كبيرا (Uppercase)، بغضّ النظر عن الطريقة التي أدخلهما بها المستخدم.

يمكن أيضا استخدام المسترجعات لدمج خاصيّتين في النموذج لتكوّنا واحدة جديدة. يمكن مثلا تعريف الاسم الكامل full_name بناء على الاسم الشخصي والاسم العائلي:

/**
* Get members full name
* 
* @return string
*/
public function getFullNameAttribute()
{
  return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
}

ثم يمكننا استخدامه كما لو كان فعلا يوجد حقل باسم full_name في النموذج:

$member = App\Member::find(1);

echo $member->full_name;

يمكنك إن أردت استخدام المسترجعات على أنواع بيانات أخرى. مثلا، لتهيئة التاريخ. نستخدم في المثال التالي الدالة getLastLoginAttribute لتهيئة تاريخ آخر دخول (الحقل last_login) بحيث يظهر بالصيغة d.m.Y (يمثّل الحرف d اليوم، الحرفm الشهر وY السنة مكتوبة بأربعة أرقام):

/**
 * Custom format for the last login date
 * 
 * @param $value
 * @return string
 */
public function getLastLoginAttribute($value)
{
    return \Carbon\Carbon::parse($value)->format('d.m.Y.');
}

ثم نستخدم الحقل last_login كما في المثال التالي:

$member = App\Member::find(1);
echo $member->last_login;

يظهر الحقل كما يلي:

11.07.2016.

تعريف معدل

تشبه آلية تسميّة المعدِّل تعريفَ المسترجع، مع فرق إحلال set مكان get. إذا أردنا تعريف معدِّل للخاصيّة foo فسيكون اسمُه setFooAttribute. نعود لمثال النموذج Member السابق. نريد الآن أن نتأكد من تهيئة اسم العضو قبل حفظ النموذج في قاعدة البيانات:

/**
* التأكد من تهيئة الاسم الشخصي **قبل** حفظ النموذج
* 
* @param $value
* @return string
*/
public function setFirstNameAttribute($value)
{
    $this->attributes['first_name'] = ucfirst($value);
}

/**
* التأكد من تهيئة الاسم العائلي **قبل** حفظ النموذج
* 
* @param $value
* @return string
*/
public function setLastNameAttribute($value)
{
    $this->attributes['last_name'] = ucfirst($value);
}

ربما لاحظت أن الدالة لا ترجِع أية قيمة. ما يحدُث هو أننا نضبُط الخاصيّة بالقيمة التي نريد مباشرة. نتأكد بهذه الطريقة أن الاسمين الشّخصي والعائلي سيكونان مهيأيْن دائما بالصيغة التي نريد.

أمثلة على المسترجعات والمعدلات

رأينا في الفقرات السابقة أمثلة لاستخدامات سهلة للمسترجعات والمعدّلات؛ إلا أن هذه الدوال يمكن أن تُستخدَم لأمور أكثر تخصيصا كما سنرى في الأمثلة التالية.

حماية كلمات السّر

يمكن استخدام المعدِّلات لتجزئة كلمة السّر Password hashing قبل حفظها في قاعدة البيانات؛ مثلا:

public function setPasswordAttribute($value) {
    $this->attributes['password'] = Hash::make($value);
}

تتأكد بهذه الطريقة أن كلمة السّر لن تُحفَظ أبدا بصيغتها المقروءة في قاعدة البيانات، وهو ما يعدّ إجراء أمنيًّا أساسيا. استخدمنا في المثال السابق صنف Hash الذي يوفّره Laravel مبدئيا، ولكن يمكنك استخدام دوال تعميّة إن أردت، مثل ()bcrypt.

الترميز بصيغة Json

إن نظرت إلى نموذج Member السابق فستجد أنه يحوي خاصيّة باسم settings تُستخدَم لحفظ تفضيلات العضو الشخصيّة وخيارات أخرى يتيحها التطبيق. يمكن استخدام مصفوفة لإدارة هذه الخيارات وحفظها في قاعدة البيانات بصيغة Json. تتيح قواعد بيانات مثل PostgreSQL نوع البيانات Json في حقول الجدول منذ زمن، كما أن MySQL أتاحت نوع البيانات هذا في الإصدار 5.7.8.

ملحوظة: دعم نوع البيانات Json في MySQL لا زال في بداياته، وقد تواجه مشاكل عند استخدامه.

بالنسبة لخاصيّة settings فسنحتاج لمعدِّل يخزّن البيانات بصيغة Json في القاعدة ومسترجِع لتحويل Json إلى مصفوفة من سلسلة محارف:

/**
* Make sure that we get an array from JSON string 
*
* @param $value
* @return array
*/
public function getSettingsAttribute($value) {
    return json_decode($value, true);
}


/**
* Encode an array to a JSON string
* 
* @param $value
*/
public function setSettingsAttribute($value)
{
    $this->attributes['settings'] = json_encode($value);
}

المثال كاملا

في ما يلي الخطوات اللازمة لإنشاء مثال عملي يعتمد على النموذج المقدّم في هذا الدرس. نفترض وجود Laravel مثبّت بقاعدة بيانات مضبوطة.

إنشاء التهجير والنموذج

php artisan make:model Member -m
Model created successfully.
Created Migration: 2016_07_04_020531_create_members_table

التعديل على التهجير

public function up()
    {
        Schema::create('members', function (Blueprint $table) {
            $table->increments('id');
            $table->string('first_name');
            $table->string('last_name');
            $table->string('email');
            $table->string('password');
            $table->date('last_login');
            $table->string('settings');
            $table->timestamps();
        });
    }

التعديل على النموذج

في ما يلي الشفرة الكاملة للنموذج Member مع المسترجعات والمعدِّلات.

<?php  namespace App;

use Illuminate\Support\Facades\Hash;
use Illuminate\Database\Eloquent\Model;

/**
* Class Member
* @package App
*/
class Member extends Model
{
    /**
    * @var array
    */
    protected $fillable = ['first_name', 'last_name', 'email', 'password', 'last_login', 'settings', 'created_at', 'updated_at'];

    /**
    * التأكد من تهيئة الاسم الشخصي بعد الحصول على النموذج من قاعدة البيانات
    *
    * @param $value
    * @return string
    */
    public function getFirstNameAttribute($value)
    {
        return ucfirst($value);
    }

    /**
    * التأكد من تهيئة الاسم العائلي بعد الحصول على النموذج من قاعدة البيانات
    *
    * @param $value
    * @return string
    */
    public function getLastNameAttribute($value)
    {
        return ucfirst($value);
    }

    /**
    * الاسم الكامل للعضو
    *
    * @return string
    */
    public function getFullNameAttribute()
    {
        return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
    }

    /**
    * تهيئة تاريخ آخر زيارة
    *
    * @param $value
    * @return string
    */
    public function getLastLoginAttribute($value)
    {
        return \Carbon\Carbon::parse($value)->format('d.m.Y.');
    }

    /**
    *  التأكد من تهيئة الاسم الشخصي **قبل** حفظ النموذج
    *
    * @param $value
    * @return string
    */
    public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = ucfirst($value);
    }

    /**
    * التأكد من تهيئة الاسم العائلي **قبل** حفظ النموذج
    *
    * @param $value
    * @return string
    */
    public function setLastNameAttribute($value)
    {
        $this->attributes['last_name'] = ucfirst($value);
    }

    /**
    * تهيئة كلمة السّر **قبل** حفظها
    *
    * @param $value
    */
    public function setPasswordAttribute($value) {
        $this->attributes['password'] = Hash::make($value);
    }

    /**
    * الحصول على مصفوفة من حقل بصيغة 
    * Json
	*
    * @param $value
    * @return array
    */
    public function getSettingsAttribute($value) {
        return json_decode($value, true);
    }


    /**
    * الترميز بصيغة 
    * Json
	* قبل حفظ الحقل
    * @param $value
    */
    public function setSettingsAttribute($value)
    {
        $this->attributes['settings'] = json_encode($value);
    }

}

استخدام النموذج

Route::get('members', function() {
    $user = App\Member::create([
        'first_name'  => 'mirza',
        'last_name'   => 'pasic',
        'email'       => 'mirza.pasic@bosnadev.com',
        'password'    => '!supersecretpassword!',
        'last_login'  => Carbon\Carbon::now(),
        'settings'    => ['two_factor_aut' => true, 'session_time' => 1200],
        'created_at'  => Carbon\Carbon::now(),
        'updated_at'  => Carbon\Carbon::now()
    ]);

    $member = App\Member::find(1);
    echo $member->last_login . '<br>';
    echo $member->full_name . '<br>';
});

ترجمة -وبتصرّف- للمقال Laravel Accessors and Mutators لصاحبه Mirza Pasic.



1 شخص أعجب بهذا


تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن