اكتشف إطار PHP Laravel


الدرس: طرق عرض نظيفة (1/2)


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

وحدات الماكرو Macros


المشكلة
انظر إلى طريقة العرض التي أنشأناها في مثال المدونة الشخصية لإنشاء المقالة ( resources/views/posts/add.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">Ajout d'un article</div>
            <div class="panel-body"> 
                {!! Form::open(['route' => 'post.store']) !!}
                    <div class="form-group {!! $errors->has('titre') ? 'has-error' : '' !!}">
                        {!! Form::text('titre', null, ['class' => 'form-control', 'placeholder' => 'Titre']) !!}
                        {!! $errors->first('titre', '<small class="help-block">:message</small>') !!}
                    </div>
                    <div class="form-group {!! $errors->has('contenu') ? 'has-error' : '' !!}">
                        {!! Form::textarea ('contenu', null, ['class' => 'form-control', 'placeholder' => 'Contenu']) !!}
                        {!! $errors->first('contenu', '<small class="help-block">:message</small>') !!}
                    </div>
                    <div class="form-group { { $errors->has('tags') ? 'has-error' : '' }}">
                        {!! Form::text('tags', null, array('class' => 'form-control', 'placeholder' => 'Entrez les tags séparés par des virgules')) !!}
                        {!! $errors->first('tags', '<small class="help-block">:message</small>') !!}
                    </div>
                    {!! Form::submit('Envoyer !', ['class' => 'btn btn-info pull-right']) !!}
                {!! Form::close() !!}
            </div>
        </div>
        <a href="javascript:history.back()" class="btn btn-primary">
            <span class="glyphicon glyphicon-circle-arrow-left"></span> Retour
        </a>
    </div>
@endsection
كيف تعتمد Bootstrap على هذا الكود؟ نقطة صغيرة:
  • تخطيط مع الشبكة ،
  • استخدام المكون panel،
  • باستخدام الطبقات btn، btn-info، form-control، form-group... للنموذج،
  • استخدام الفصل has-error  لإعادة التحقق من الصحة ،
إذا قررت تغيير الإطار ، يجب أن أبدأ من جديد. إذا كان لدي شكل واحد فقط من هذا النوع ، فهو ليس خطيرًا جدًا ، إذا كان لدي 10 أو 20 فسيصبح محرجًا. بنفس الطريقة إذا تطور الإطار (وهو أمر متكرر على سبيل المثال مع Bootstrap ) وأرغب في متابعة هذا التطور ، فسوف أواجه نفس المشكلة.
المثالي هو أن تكون قادرًا على بناء العرض (View) دون أي ارتباط بإطار مع أساليب محايدة. كيف يمكنك أن تفعل ذلك؟ هناك العديد من الطرق للقيام بذلك ، ولكن أسهل طريقة هي استخدام وحدات الماكرو.
وحدات الماكرو
الماكرو أداة بديلة: نستخدم نصًا واحدًا وينشئ نصًا آخر مع إمكانية تمرير مُدخلات .  Laravel يسمح بإنشاء وحدات ماكرو. ابحث في ملفات الإطار للعثور على هذا الملف:
framework Laravel MVC
ملف وحدات الماكرو
إذا نظرت إلى الكود ، فسترى أنه سمة تكشف بعض الطرق بما في ذلك:

<?php
public static function macro($name, callable $macro)
{
    static::$macros[$name] = $macro;
}
باستخدام هذه الخاصية ، يمكننا تسجيل وحدات الماكرو في الخاصية الثابتة $macros . هناك أيضًا طرق سحرية لاستخدام وحدات الماكرو المخزنة.
اتضح أن المكون LaravelCollective\Html  يستخدم هذه الخاصية. على سبيل المثال في الفصل FormBuilder  نجد:

<?php
class FormBuilder {

    use Macroable, Componentable {
        Macroable::__call as macroCall;
        Componentable::__call as componentCall;
    }
هو نفسه للفصل HtmlBuilder . لذلك سوف نستخدم هذا الاحتمال لجعل نظرتنا أكثر نظافة ...
نريد أن نصل مع وجهة نظر تصور بالتالي: 

@extends('template')

@section('contenu')
    <br>
    <div class="col-sm-offset-3 col-sm-6">
        <div class="panel panel-info">
            <div class="panel-heading">Ajout d'un article</div>
            <div class="panel-body"> 
                {!! Form::open(['route' => 'post.store']) !!}
                    {!! Form::control('text', $errors, 'titre', 'Titre') !!}
                    {!! Form::control('textarea', $errors, 'contenu', 'Contenu') !!}
                    {!! Form::control('text', $errors, 'tags', 'Entrez les tags séparés par des virgules') !!}
                    {!! Form::button_submit('Envoyer !') !!}
                {!! Form::close() !!}
            </div>
        </div>
        {!! Html::button_back() !!}
    </div>
@endsection
لم يعد لدينا أي أثر لإطار عملنا على مستوى النموذج.
الآن السؤال هو: أين تضع وحدات الماكرو؟
مزود الخدمة service provider
مزود الخدمة هو المكان المثالي لتسجيل الخدمات. لدى Laravel العديد من مقدمي الخدمات. سنقوم بإنشاء واحد لوحدات الماكرو الخاصة بنا. مرة أخرى سوف نستخدم Artisan لتسهيل مهمتنا:

php artisan make:provider HtmlMacrosServiceProvider
نجد مزودنا في المجلد المقابل:
framework Laravel MVC
مزود وحدات الماكرو
مع هذا الكود:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class HtmlMacrosServiceProvider extends ServiceProvider
{

    /**
     * Bootstrap the application services.
     *
     * @return  void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return  void
     */
    public function register()
    {
        //
    }

}
Register  تتيح لك هذه الطريقة تسجيل كل ما تحتاجه ، لذلك وحدات الماكرو لدينا.
boot  يتم تنفيذ هذه الطريقة بمجرد تسجيل جميع مقدمي التطبيق ، مما يجعل من الممكن الحصول على جميع الخدمات.
لذلك سننشئ وحدات الماكرو الخاصة بنا هنا:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Collective\Html\FormBuilder;
use Collective\Html\HtmlBuilder;

class HtmlMacrosServiceProvider extends ServiceProvider
{

    public function register()
    {
        $this->registerFormControl();
        $this->registerFormSubmit();
        $this->registerHtmlButtonBack();
    }

    private function registerFormControl()
    {
        FormBuilder::macro('control', function($type, $errors, $nom, $placeholder)
        {
            $valeur = \Request::old($nom) ? \Request::old($nom) : null;
            $attributes = ['class' => 'form-control', 'placeholder' => $placeholder];
            return sprintf('
                
%s %s
', $errors->has($nom) ? 'has-error' : '', call_user_func_array(['Form', $type], [$nom, $valeur, $attributes]), $errors->first($nom, ':message') ); }); } private function registerFormSubmit() { FormBuilder::macro('button_submit', function($texte) { return FormBuilder::submit($texte, ['class' => 'btn btn-info pull-right']); }); } private function registerHtmlButtonBack() { HtmlBuilder::macro('button_back', function() { return '<a href="javascript:history.back()" class="btn btn-primary"> <span class="glyphicon glyphicon-circle-arrow-left"></span> Retour </a>'; }); } }
هذا مجرد مثال ويمكن أن يكون الترميز مختلفًا ، إنه المبدأ الذي يهمنا. يمكننا أيضًا تحديد موقع وحدات الماكرو في مكان آخر والاتصال به من مقدم الخدمات (provider) . لذلك فهي مجرد مسألة تنظيم للكود. من الواضح أن مقدمي الخدمات لم يُصنعوا لاستيعاب الأكواد الكبيرة ، مثل كل فئات . كجزء من هذه الدورة التدريبية ، سنكتفي بهذا العرض التقديمي. 
يبقى فقط إبلاغ Laravel بأن مقدم الخدمات لدينا موجود في config/app.php  :

<?php
/*
 * Application Service Providers...
 */
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
Collective\Html\HtmlServiceProvider::class,
App\Providers\HtmlMacrosServiceProvider::class,
عادة يجب أن لا يزال نموذج إنشاء المقالة يعمل:
framework Laravel MVC
النموذج الذي تم إنشاؤه بواسطة وحدات الماكرو
تمكنا من تنظيف طريقة العرض على مستوى النموذج.

القوالب templates


ولكن لا تزال هناك عناصر من الإطار في رأينا: الشبكة (grille) واللوحة.(panel) لن يتم تكييف ماكرو فعليًا ، فمن الأفضل إنشاء قالب لهذا النموذج يمكن استخدامه للنماذج الأخرى ( app/views/template_form.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">
                @yield('titre')
            </div>
            <div class="panel-body"> 
                @yield('formulaire')
            </div>
        </div>
        {!! Html::button_back() !!}
    </div>
@stop
أذكرك بمحتوى القالب الرئيسي ( app/views/template.blade.php) :

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Mon joli site</title>
        {!! HTML::style('https://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css') !!}
        {!! HTML::style('https://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css') !!}
        <!--[if lt IE 9]>
            { { HTML::style('https://oss.maxcdn.com/libs/html5shiv/3.7.2/html5shiv.js') }}
            { { HTML::style('https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js') }}
        <![endif]-->
        <style> textarea { resize: none; } </style>
    </head>
    <body>
        <header class="jumbotron">
            <div class="container">
                <h1 class="page-header">{!! link_to_route('post.index', 'Mon joli blog') !!}</h1>
                @yield('header')
            </div>
        </header>
        <div class="container">
            @yield('contenu')
        </div>
    </body>
</html>
الآن يمكننا الحصول على طريقة عرض دقيقة للغاية لشكلنا:

@extends('template_form')

@section('titre')
    Ajout d'un article
@stop

@section('formulaire')
    {!! Form::open(['route' => 'post.store']) !!}
        {!! Form::control('text', $errors, 'titre', 'Titre') !!}
        {!! Form::control('textarea', $errors, 'contenu', 'Contenu') !!}
        {!! Form::control('text', $errors, 'tags', 'Entrez les tags séparés par des virgules') !!}
        {!! Form::button_submit('Envoyer !') !!}
    {!! Form::close() !!}
@endsection
لا مزيد من تتبع الإطار. بغض النظر عن تعديلات الواجهة اللاحقة ، لن يتعين تعديل طريقة العرض هذه. إذا قمنا بتغيير الإطار ، فلدينا فقط القالب العام والنماذج المراد تعديلها.
يجب عليك تنظيم القوالب الخاصة بك بشكل جيد للحصول على كود فعال ، والذي يعتمد بوضوح على التطبيق الخاص بك.
إذا كان لديك الكثير من المشاهدات ، فمن المستحسن إنشاء مجلدات لتنظيمها. على سبيل المثال ، يمكنك إنشاء مجلد "templates" .
يمكن أن يؤدي تنظيم آخر للكود إلى إنشاء طرق عرض جزئية لإدراجها في العرض النهائي ، وهذا ما يسمى "partials" . يستخدم على نطاق واسع على سبيل المثال في أشرطة رسالة الخطأ. هناك طرق عديدة لتنظيم العروض ، والشيء الرئيسي هو الوصول إلى كود بسيط وقابل للقراءة وسهل الصيانة.

في الخلاصة


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