لارافيل, Others / 2024-11-23

تخزين إعدادات الموقع في قاعدة البيانات مع إستخدام Caching في لارافيل

تخزين إعدادات الموقع في قاعدة البيانات مع إستخدام Caching في لارافيل

2024-11-23 وقت القراءه : 5 دقائق

في أي موقع إلكتروني، هناك بعض الإعدادات التي يجب أن يتحكم بها صاحب الموقع ( العميل )،  والتي تكون مشتركه في جميع الصفحات مثل إسم الموقع <title> و <description> وغيرها من الإعدادات، فمن غير المعقول أنه عند كل عملية تنقل بين الصفحات أن يتم جلب البيانات من قاعدة البيانات، الحل هنا يكمن في حفظ هذه البيانات في قاعدة البيانات ، مع إستخدام caching.

في هذا المثال، سنرى كيف يمكن عمل ذلك، دون إستخدام أي حزم packages.

1- إنشاء Setting Model و Migration و SettingController وكذلك SettingSeeder class 

php artisan make:model Setting -mcs

في ملف migration سيتم إضافة الحقلين key و value، لكن يجب أن يكون key = unique وأن لا يكون null، وذلك لأنه به سيتم تخزين المفتاتيح مثل site_name, site_description و بـ الـ value سيتم تخزين القيمة.

public function up(): void
{
    Schema::create('settings', function (Blueprint $table) {
        $table->id();
        $table->string('key')->unique();
        $table->string('value')->nullable();
        $table->timestamps();
    });
}

الأن نحتاج في Setting Model أن يتم إضافة key, value إلى fillable.

class Setting extends Model
{
    use HasFactory;
    protected $fillable = ['key', 'value'];
}


الأن تحضير البيانات في ملف SettingSeeder

class SettingSeeder extends Seeder
{
    public function run(): void
    {
        $settings = [
            ['key' => 'site_name', 'value' => 'Palestine'],
            ['key' => 'description', 'value' => 'Palestine Will be free.'],
            ['key' => 'keyword', 'value' => 'palestine, aqsa, jerusalem, occupation'],
            ['key' => 'admin_email', 'value' => 'admin@admin.com'],
            ['key' => 'posts_per_page', 'value' => 10],
            ['key' => 'users_can_register', 'value' => true],
        ];
        Setting::insert($settings);
    }
}


الأن إستدعاء الكلاس SettingSeeder في الكلاس DatabaseSeeder 

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            SettingSeeder::class,
        ]);
    }
}

وأخيرا، تنفيذ الأمر migrate --seed حتى يتم إنشاء الجدول settings وإدخال البيانات في هذا الجدول.

php artisan migrate --seed


2- تحضير Controller, Routes و View

بداية سيتم تحضير routes في الملف web.php ومن ثم تحضير الدوال edit و update في Setting Controller، ومن ثم تحضير ملف settings.blade.php

تحضير الـ route في ملف routes/web.php

use App\Http\Controllers\SettingsController;
 
Route::middleware('auth')->group(function () {
    Route::get('/settings', [SettingsController::class, 'edit'])->name('settings.edit');
    Route::post('/settings', [SettingsController::class, 'update'])->name('settings.update');
});


class SettingController extends Controller
{
    public function edit()
    {
        return view('settings', [
            'settings' => Setting::get(['key', 'value'])
        ]);
    }


    public function update(Request $request)
    {
        $data = $request->except('_token');
        foreach ($data as $key => $value) {
            Setting::where('key', $key)->update(['value' => $value]);
        }
        return to_route('settings.edit')
            ->withStatus('Settings updated successfully.');
    }
}

إنشاء ملف serrings.blade.php من أجل عرض البيانات وكذلك فورم التعديل.

<div class="container">
    @if(session('status'))
        <div class="alert alert-info">{{ session('status') }}</div>
    @endif
    <form method="post" action="{{ route('settings.update') }}">
        @csrf
        @foreach($settings as $setting)
            <div class="form-floating mb-3">
                <input 
                    type="text" 
                    class="form-control" 
                    value="{{ $setting->value }}" 
                    name="{{ $setting->key }}" 
                    id="{{ $setting->key }}">
                <label for="{{ $setting->key }}">{{ $setting->key }}</label>
            </div>
        @endforeach

        <button class="btn btn-success">
            Update Settings
        </button>
    </form>
</div>

وبذلك نحصل على هذا الشكل

وبذلك نكون قد إنتهينا من عرض الحقول وإمكانية التعديل عليها.


3- عمل Caching

لجلب قيمة key معين من قاعدة البيانات 

Setting::where('key', 'site_name')->first();

 لكن هذه الجمله يتم تنفيذها وإنشاء DB query في كل مره، ولجلب جميع البيانات مره واحده وعمل cach لها.

يمكن لنا القيام بذلك من خلال الذهاب للدالة boot في الكلاس AppServiceProvider

app/Providers/AppServiceProvider.php

public function boot(): void
{
    $this->app->bind('settings', function () {
        return Cache::rememberForever('settings', function () {
            return Setting::pluck('value', 'key');
        });
    });
}

الأن يمكن لنا عرض البيانات بالشكل التالي 

app('settings')['site_name'];
<title>{{ app('settings')['site_name'] }}</title>


لكن الأن لو قام صاحب الموقع بالتعديل على site_name, site_keyword فإنه بالفعل سيتم تعديل ذلك في قاعدة البيانات، لكن في العرض سيتم عرض البيانات القديمه، وذلك لأنه تم عمل cache لها، والحل هنا يكون بإستخدام Cache::forget.

public function update(Request $request)
{
    $data = $request->except('_token');


    foreach ($data as $key => $value) {
        Setting::where('key', $key)->update(['value' => $value]);
    }


    Cache::forget('settings');
    return to_route('settings.edit')
        ->withStatus('Settings updated successfully.');
}


4- إنشاء helper لجلب البيانات

جلب البيانات من الـ container بشكل مباشر  غير مريح

app('settings')['site_name']

لذلك يمكن لنا إنشاء helper حيث نقوم بإنشاء folder بإسم helpers بداخل المجلد app وبداخل المجلد helpers ننشئ الدالة settings.

app/Helpers/settings.php

وبداخل هذه الداله

<?php
if (! function_exists('settings')) {
    function settings(?string $key = null, $default = null)
    {
        if (is_null($key)) {
            return app('settings');
        }


        return app('settings')->get($key, $default);
    }
}
?>

ومن ثم إضافة مسار هذه الملف إلى autoload helpers في الملف composer.json

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "Database\\Factories\\": "database/factories/",
        "Database\\Seeders\\": "database/seeders/"
    },
    "files": [
        "app/Helpers/settings.php"
    ]
},

ومن ثم تنفيذ الأمر

composer dump-autoload

الأن يمكن لنا الوصول إلى أي value بشكل مباشر 

{{ settings('site_name') }}
<title>{{ settings('site_name') }}</title>


4- إضافة المزيد من الحقول إلى ملف migration

إذا أردنا إضافة المزيد من الحقول إلى ملف migrations، يجب أن لا ننسى مسح الكاش، وذلك من خلال إضافة cache::forget

return new class extends Migration {
    public function up(): void
    {
        $data = [
            ['key' => 'start_of_week', 'value' => 1],
            ['key' => 'show_testimonials', 'value' => true],
            ['key' => 'allow_comments', 'value' => false],
        ];
 
        Setting::insert($data);
 
        Cache::forget('settings');
    }
};


5- حزم Packages للتعامل مع إعدادات الموقع 

يوجد مجموعه من الحزم التي تساعدنا في إعدادات الموقع، ومنها:-

https://github.com/spatie/valuestore

https://github.com/qcod/laravel-settings

هل ترغبون في عمل شرح لهذه الحزم.

إقرأ أيضا: 

كيفية عمل CACHE في LARAVEL لجمل الإستعلام في لارافيل أسرع وتحسين أداء الموقع


التعليقات
زائر
منذ سنة

مشكور على هذا المقال الرائع

Mohammad Salloum
منذ سنة

شكرا على هذه المقالة المفيدة

زائر
منذ سنة

ممتاز جدااا

إضافة تعليق
Loading...