اكتشف إطار PHP Laravel


الدرس: الترحيل والنماذج Migration and models


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

الترحيل Migration


يتيح لك الترحيل إنشاء مخطط قاعدة بيانات وتحديثه. بمعنى آخر ، يمكنك إنشاء جداول ، أعمدة في هذه الجداول ، حذفها ، إنشاء فهارس ... كل ما يتعلق بصيانة الجداول الخاصة بك يمكن العناية به من خلال هذه الأداة.
اعدادات قاعدة البيانات
يجب أن يكون لديك أولاً قاعدة بيانات. يتيح لك Laravel إدارة قواعد البيانات مثل MySQL و Postgres و SQLite و SQL Server . سأقوم بكل الأمثلة مع MySQL ، لكن جميع الاكواد ستكون صالحة أيضًا للأنواع الأخرى من قواعد البيانات.
يجب أن تشير إلى مكان قاعدتك واسمها واسم المستخدم وكلمة المرور في ملف الاعدادات .env  :

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
هنا لدينا القيم التلقائية عند تثبيت Laravel .
هنا ، على سبيل المثال ، الإعدادات الخاصة بي لقاعدة بيانات اختبار MySQL تسمى "tuto" مع MySQL في موقع غير آمن:

DB_DATABASE=tuto
DB_USERNAME=root
DB_PASSWORD=
Artisan
Laravel لديه أداة سطر الأوامر:  Artisan . لقد استخدمنا بالفعل هذه الأداة التي تتيح لك القيام بأشياء كثيرة ، لديك نظرة عامة على الأوامر عن طريق إدخال:

php artisan
لديك قائمة طويلة. بالنسبة لهذا الفصل ، سنركز فقط على تلك المتعلقة بالترحيل:

Make
...

make:migration     Create a new migration file
...

migrate
 migrate:install    Create the migration repository
 migrate:refresh    Reset and re-run all migrations
 migrate:reset      Rollback all database migrations
 migrate:rollback   Rollback the last database migration
 migrate:status     Show a the status of each migration
تثبيت الترحيل
سنبدأ بتثبيت الترحيل:

php artisan migrate:install
Migration table created successfully.
إذا نظرت إلى التأثير في قاعدة البيانات الخاصة بك سترى أنه تم إنشاء جدول:
framework Laravel MVC
جدول الترحيل
في هذا الجدول سيتم حفظ جميع الإجراءات الخاصة بك على مستوى مخطط قاعدة البيانات.
إنشاء الترحيل
الخطوة الثانية هي إنشاء الترحيل لجدولنا:

php artisan make:migration create_emails_table
Created Migration: 2015_01_15_121123_create_emails_table
إذا نظرت الآن في المجلد database/migrations ، فستجد ملفًا مثل هذا  2015_12_27_210631_create_emails_table.php  (من الواضح أن الجزء الرقمي الذي يتضمن التاريخ سيكون مختلفًا عندك) :
framework Laravel MVC
الترحيل التي تم إنشاؤها
ولكن هناك بالفعل الترحيلات الحالية ، ماذا عنهم؟
هناك بالفعل 2 ترحيلات موجودة بالفعل:
  • الجدول users : هذا ترحيل أساسي لإنشاء جدول مستخدم ،
  • الجدول password_resets : هذا ترحيل مرتبط بالنقطة السابقة التي تتيح لك إدارة تجديد كلمات المرور بأمان تام.
سنركز على عمليات الترحيل هذه عندما نرى المصادقة في فصل لاحق. نظرًا لأننا لن نحتاج إلى عمليات الترحيل هذه فورًا ، فمن الأفضل حذفها في الوقت الحالي لتجنب إنشاء جداول غير ضرورية.
فيما يلي محتوى الترحيل الذي أنشأناه للتو:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateEmailsTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return  void
     */
    public function up()
    {
        //
    }

    /**
     * Reverse the migrations.
     *
     * @return  void
     */
    public function down()
    {
        //
    }

}
هناك وظيفتان في هذه الفئة: 
  • up  : هنا سنضع كود الانشاء
  • down  : هنا سوف نضع كود الحذف
نرغب في إنشاء جدول "رسائل بريد إلكتروني" مع معرف زيادة ذاتية وحقل "بريد إلكتروني" من نوع النص ، وبطول 100. إليك الكود اللازم :

<?php
public function up()
{
    Schema::create('emails', function(Blueprint $table) {
        $table->increments('id');
        $table->string('email', 100);
    });
}
نطلب من أداة انشاء (constructor) المخطط ( Schema) إنشاء ( create) جدول "emails" . في الوظيفة المجهولة ، نحدد ما نريد للجدول:
  • عمود "id" تلقائي تلقائيًا ، وبالتالي سيكون المفتاح الأساسي للجدول ،
  • عمود "email" من النوع سلسلة والطول 100.
بالنسبة للطريقة ، down  سنقوم بحذف الجدول فقط باستخدام drop  :

<?php
public function down()
{
    Schema::drop('emails');
}
تم إنشاء الترحيل لدينا الآن.
استخدام الترحيل
سنبدأ الآن عملية الترحيل (استخدام طريقة   الترحيل up ) :

php artisan migrate
Migrated: 2015_12_27_210631_create_emails_table
إذا نظرنا الآن في قاعدة البيانات ، نجد جدول "emails" بهذين العمودين:
framework Laravel MVC
جدول "emails"
إذا ارتكبت خطأ ، فيمكنك العودة بـ rollback  الذي يلغي آخر ترحيل تم تنفيذه (استخدام طريقة   الترحيل down)

php artisan migrate:rollback
Rolled back: 2015_12_27_210631_create_emails_table
تم حذف الجدول الآن من قاعدة البيانات. نظرًا لأننا سنحتاج إلى هذا الجدول ، فسنقوم بإعادة التشغيل. يمكنك أيضًا تحديث جميع عمليات الترحيل باستخدام الأمر refresh  (التراجع عن جميع عمليات الترحيل وإعادة تشغيل جميع عمليات الترحيل) .

Eloquent


يقدم Laravel ORM (اختصار acronyme de object-relational mapping  أو في العربية تعيين كائن العلائقية) . بم يتعلق الأمر ؟ بكل بساطة أن جميع عناصر قاعدة البيانات لها تمثيل في شكل كائنات قابلة للإدارة. ما الفائدة؟ بكل بساطة لتبسيط العمليات بشكل كبير على القاعدة كما سنرى في هذا الجزء كله من الدورة.
مع Eloquent ، يتم تمثيل الجدول بفئة تمتد الفئة النموذجية. لجدول أعمالنا   emails ونحن مرة أخرى سنستخدم Artisan لإنشاء المُجسم:

php artisan make:model Email
يمكنك العثور على الملف هنا:
framework Laravel MVC
المُجسم الجديد لرسائل البريد الإلكتروني
مع هذا الإطار الأساسي:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Email extends Model
{
    //
}
سنكمل الكود كما يلي:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Email extends Model 
{
    
    protected $table = 'emails';
    
    public $timestamps = false;

}
ترى انها بسيطة جدا! ندخل اسم الجدول المرتبط بالمُجسم. وعلاوة على ذلك يقوم Eloquent تلقائيا بتحديث الأعمدة created_at  و updated_at  في الجدول. بما أننا لم نخطط ، لإلغاء تنشيط هذا الإجراء ، فنحن مضطرون لوضع false   للخاصية timestamps .  سنضع هذا المُجسم مباشرة في المجلد app، ومن الواضح أنه بالنسبة للتطبيق الحقيقي ، سننظم المجلدات لتخزين جميع ملفاتنا بشكل صحيح ولكن في الوقت الحالي سنبسطها.
إذا لم نضع الخاصية $table  فان Laravel سوف يستنتج اسم الجدول من اسم المُجسم. بمعنى آخر ، في حالتنا ، يمكننا تجنب سطر التعليمات البرمجية هذا.
سنرى الآن كيفية استخدام هذه الفئة عند إنشاء تطبيقنا الصغير.
التحقق من صحة
للتحقق من الصحة ، سنواصل إنشاء طلب نموذج:

php artisan make:request EmailRequest
Request created successfully.
نجد الطلب في ملفه:
framework Laravel MVC
طلب النموذج
هنا هو مع كود الانتهاء:

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class EmailRequest extends Request
{

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return  bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return  array
     */
    public function rules()
    {
        return ['email' => 'required|email|unique:emails'];
    }

}
لدينا 3 قواعد:
  • required  : الحقل مطلوب ،
  • email  : يجب أن يكون لدينا عنوان بريد إلكتروني صالح ،
  • unique  : يجب ألا يكون البريد الإلكتروني موجودًا بالفعل ( unique) في الجدول emails  (نعني أنه العمود email ) .
لاحظ قوة القاعدة الثالثة: سوف يتحقق Eloquent من عدم وجود بريدنا الإلكتروني بالفعل في الجدول! 
الطرق Route
سيكون لدينا طريقان:

<?php
Route::get('email', 'EmailController@getForm');
Route::post('email', ['uses' => 'EmailController@postForm', 'as' => 'storeEmail']);
لاحظ أن المسار الثاني يدعى ( storeEmail ) .
سيكون عنوان url الأساسي بالتالي:

http://monsite.fr/email
وحدة التحكم
سننشئ وحدة تحكم EmailController  :
framework Laravel MVC
وحدة تحكم EmailController
يتناول كود التحكم معظم ما رأيناه في الفصول السابقة باستخدام التحقق من الصحة المحقن مرة أخرى:

<?php

namespace App\Http\Controllers;

use App\Email;
use App\Http\Requests\EmailRequest;

class EmailController extends Controller
{

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

    public function postForm(EmailRequest $request)
    {
        $email = new Email;
        $email->email = $request->input('email');
        $email->save();
        
        return view('email_ok');
    }

}
الشيء الجديد يكمن فقط في استخدام النموذج:

<?php
$email = new Email;
$email->email = $request->input('email');
$email->save();
نحن هنا نقوم بإنشاء مثيل جديد من Email . يتم تعيين السمة  email بقيمة الإدخال. أخيرًا نطلب من المُجسم حفظ هذا الخط بفعالية في الجدول ( save) .
العرض views
سوف نستخدم نفس tempate كما في الفصول السابقة. فيما يلي عرض النموذج (resources/views/email.blade.php) :

@extends('template')

@section('contenu')
    <br>
    <div class="col-sm-offset-4 col-sm-4">
        <div class="panel panel-info">
            <div class="panel-heading">Inscription à la lettre d'information</div>
            <div class="panel-body"> 
                {!! Form::open(['route' => 'storeEmail']) !!}
                    <div class="form-group {!! $errors->has('email') ? 'has-error' : '' !!}">
                        {!! Form::email('email', null, array('class' => 'form-control', 'placeholder' => 'Entrez votre email')) !!}
                        {!! $errors->first('email', '<small class="help-block">:message</small>') !!}
                    </div>
                    {!! Form::submit('Envoyer !', ['class' => 'btn btn-info pull-right']) !!}
                {!! Form::close() !!}
            </div>
        </div>
    </div>
@endsection
ليس لهذا العرض شيء جديد بالنسبة لك باستثناء استخدام اسم المسار ، فهو يستجيب إلى عنوان url (مع الحصول على الفعل) :
http://monsite.fr/email
المظهر كالتالي:
framework Laravel MVC
النموذج
فيما يلي عرض التأكيد(resources/views/email_ok.blade.php):

@extends('template')

@section('contenu')
    <br>
    <div class="col-sm-offset-3 col-sm-6">
        <div class="panel panel-info">
            <div class="panel-heading">Inscription à la lettre d'information</div>
            <div class="panel-body"> 
                Merci. Votre adresse a bien été prise en compte.
            </div>
        </div>
    </div>
@endsection
مع هذا الجانب:
framework Laravel MVC
التأكيد
طريقة العمل
الآن دعونا نرى ما إذا كان كل شيء على ما يرام . أقدم عنوان:
framework Laravel MVC
تقديم العنوان
أتلقى تأكيدًا:
framework Laravel MVC
التأكيد
أنا أنظر في القاعدة:
framework Laravel MVC
العنوان في القاعدة
أرسل نفس العنوان:
framework Laravel MVC
تقديم عنوان موجود
دعونا نلقي نظرة على الطلبات التي أنشأتها Eloquent مع إرسال العنوان toto@gui.com على سبيل المثال (يمكنك العثور عليها في قسم الاستعلامات في شريط التصحيح): 

select count(*) as aggregate from `emails` where `email` = 'toto@gui.com'
insert into `emails` (`email`) values ('toto@gui.com')
الهدف من الطلب الأول هو اختبار التواجد المحتمل للعنوان في الجدول لتلبية القاعدة "unique" . الثاني يدرج السجل في الجدول. ترى أن Eloquent يبسط مهمتك ، لا تحتاج إلى كتابة استعلامات SQL ، بل يقوم بها عوضا عنك . أنت فقط تعامل مع الكائن.
لا تتردد في إلقاء نظرة على المعلومات الموجودة في شريط التصحيح ، ستجد هناك معلومات قيمة عن الطلبات ( HTTP و SQL ) ، views المستخدمة ، والطرق ، والتأخير ، والاستثناءات التي تم إنشاؤها ... لديك أيضًا سجل بالضغط على صورة الحافظة الصغيرة:
framework Laravel MVC
فتح شريط التاريخ
تنظيم الكود
الآن دعنا نسأل مرة أخرى مسألة تنظيم الكود. في وحدة التحكم نضع إدارة المُجسم:

<?php
$email = new Email;
$email->email = $request->input('email');
$email->save();
وبعبارة أخرى ، قمنا بربط وحدة التحكم والمُجسم بإحكام. لنفترض أننا قمنا بإجراء تغييرات على قاعدة البيانات الخاصة بنا ووضع البريد الإلكتروني في جدول آخر. من الواضح أنه سيتعين علينا التدخل في كود وحدة التحكم لأخذ هذا التغيير في الاعتبار.
من الواضح أنه من غير المحتمل أن يكون تعديل الكود غير مهم ... لكن لدينا هنا تطبيقًا بسيطًا للغاية ، وفي وضع حقيقي ، يكون استخدام المُجسمات عديدة ثم يصبح السؤال أكثر صلة.
الإصدار الأول
في هذه الدورة أحاول تدريبك على عادات جيدة. بدلاً من إنشاء مثيل لفئة مباشرة في فئة أخرى ، من الأفضل ضخ الحاوية والسماح لها بالقيام بالعمل. شاهد هذا الإصدار الجديد من جهاز التحكم:

<?php

namespace App\Http\Controllers;

use App\Email;
use App\Http\Requests\EmailRequest;

class EmailController extends Controller
{

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

    public function postForm(
        EmailRequest $request,
        Email $email)
    {
        $email->email = $request->input('email');
        $email->save();
        
        return view('email_ok');
    }

}
الآن يتم حقن المُجسم في الوظيفة ، فهو أكثر أناقة وفعالية. إذا قمت بتغيير المُجسم ، فلديك تغيير كود بسيط فقط على وحدة التحكم. لكنها ليست مثالية بعد. 
الإصدار الثاني
من الناحية المثالية ، نريد ألا تتأثر وحدة التحكم الخاصة بنا على الإطلاق بتغيير في إدارة المُجسم. إليك طريقة واحدة للقيام بذلك:

<?php
namespace App\Http\Controllers;

use App\Http\Requests\EmailRequest;
use App\Repositories\EmailRepository;

class EmailController extends Controller
{

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

    public function postForm(
        EmailRequest $request,
        EmailRepository $emailRepository)
    {
        $emailRepository->save($request->input('email'));
        
        return view('email_ok');
    }

}
تم الآن حقن فئة الإدارة التي لديها الأسلوب save . هنا هو العقد مع الواجهة ( app/Repositories/EmailRepositoryInterface) :

<?php

namespace App\Repositories;

interface EmailRepositoryInterface
{

    public function save($mail);
}
وهنا الفئة التي تنفذ هذه الواجهة ( app/Repositories/EmailRepository) :

<?php

namespace App\Repositories;

use App\Email;

class EmailRepository implements EmailRepositoryInterface
{

    protected $email;

    public function __construct(Email $email)
    {
        $this->email = $email;
    }

    public function save($mail)
    {
        $this->email->email = $mail;
        $this->email->save();
    }

}
يتم حقن النمُجسم في هذه الفئة. لقد وقع حقنه في أداة الانشاء (Constructor) لتعميم العملية عن طريق تخيل أننا سننشئ طرقًا أخرى يمكننا تجميعها هنا لإدارة السجلات. أصبح الكود منظمًا تمامًا وسهل التعديل والاختبار
framework Laravel MVC
الإدارة
مستودع تصميم النماذج (Design Pattern Repository) هو واحد من الأكثر شعبية. انها تسمح لك لإدارة استمرار المعلومات.
الإصدار الثالث
يمكننا أخيرًا ، كما رأينا بالفعل ، الرجوع إلى الواجهة بدلاً من الئة ولكن في هذه الحالة ، من الضروري إعلام الحاوية بالتبعية. قم بتحرير الملف كما يلي app/Http/Providers/AppServiceProvider.php  :

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

    $this->app->bind(
        'App\Repositories\EmailRepositoryInterface', 
        'App\Repositories\EmailRepository'
    );
}
وأخيرا وحدة التحكم:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\EmailRequest;
use App\Repositories\EmailRepositoryInterface;

class EmailController extends Controller
{

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

    public function postForm(
        EmailRequest $request,
        EmailRepositoryInterface $emailRepository)
    {
        $emailRepository->save($request->input('email'));
        
        return view('email_ok');
    }

}
الآن ، بما أن الحاوية تعرف الفئة التي يتم إنشاء مثيل لها من الواجهة التي تم تمريرها كمُدخل ، فلديك كود نظيف يسهل صيانته واختباره. إذا غيرت رأيك في كيفية تخزين رسائل البريد الإلكتروني ، فعليك فقط أن تقرر إنشاء مثيل لفئة أخرى من الواجهة ، طالما أن العقد مع وحدة التحكم لا يتغير!

في الخلاصة


  • يجب تكوين قاعدة البيانات للعمل مع Laravel .
  • تتيح لك عمليات الترحيل التدخل في مخطط الجداول الأساسية.
  • يسمح Eloquent بتمثيل الجداول في شكل كائنات لتبسيط معالجة السجلات.
  • من الحكمة أن تخطط لإدارة النموذج في فئة يتم حقنها في وحدة التحكم.
  • يوفر شريط التصحيح معلومات قيمة حول الاستعلامات.