Scout في Laravel

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

مقدمة

يوفر Scout حلًا بسيطًا يستند على برنامج تشغيل (Driver) لإضافة البحث عن نص كامل في نماذج Eloquent. باستخدام مراقبي النموذج (model observers)، سيحافظ Scout بشكل تلقائي على مزامنة فهارس البحث مع سجلات Eloquent الخاصة بك.

في الوقت الحالي، يأتي Scout مع برنامج التشغيل Algolia، ومع ذلك، فإن كتابة برامج تشغيل مخصصة بسيطة ولديك الحريّة في توسيع Scout مع تطبيقات البحث الخاصة بك.

التثبيت

ثبت أولًا Scout عن طريق مدير حزم Composer:

composer require laravel/scout

بعد تثبيت Scout، يجب عليك نشر ضبطه باستخدام أمر Artisan vendor:publish. وهذا الأمر سينشر ملف الضبط scout.php في مجلد config:

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

وأخيرًا، أضف سمة Laravel\Scout\Searchable إلى النموذج الذي ترغب في جعله قابلًا للبحث، وستسجل هذه السمة مراقب نموذج للحفاظ على مزامنة النموذج مع برنامج تشغيل البحث:

<?php

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model

{
   use Searchable;
}

الطابور

لا يلزم استخدام Scout بشكل صارم، لكن يجب عليك التفكير في ضبط طابور برنامج التشغيل قبل استخدام المكتبة. فبتشغيل عامل طابور، سيسمح لـ Scout بوضع جميع العمليات التي تزامن معلومات النموذج مع فهارس البحث الخاصة بك في طابور مما يوفّر وقت استجابة أفضل بكثير لواجهة الويب الخاصة بالتطبيق.

وبمجرّد ضبط برنامج تشغيل الطابور، ضع القيمة true كقيمة خيار queue في ملف الضبط config/scout.php:

'queue' => true,

متطلبات برنامج التشغيل

Algolia

عند استخدام برنامج التشغيل Algolia، يجب عليك ضبط معرّف Algolia وبيانات الاعتماد السريّة في ملف الضبط config/scout.php. وبمجرد ضبط بيانات الاعتماد الخاصة بك، ستحتاج أيضًا إلى تثبيت Algolia PHP SDK عن طريق مدير الحزم Composer:

composer require algolia/algoliasearch-client-php

الضبط

ضبط فهرسة النماذج

يتزامن كل نموذج Eloquent مع فهرس بحث معيّن، والذي يحتوي على جميع السجلات القابلة للبحث لهذا النموذج. بعبارة أخرى، يمكنك التفكير في كل فهرس على أنه جدول MySQL. وبشكل افتراضي، سيحافظ كل نموذج على فهرس يتوافق مع اسم الجدول، وعادةً ما يكون صيغة الجمع لاسم النموذج. ومع ذلك، أنت حر في تخصيص فهرس النموذج عن طريق إعادة تعريف التابع searchableAs في النموذج:

<?php

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
   use Searchable;

   /**
    * جلب اسم فهرس النموذج     *
    * @إعادة سلسلة نصية     */

   public function searchableAs()
   {
       return 'posts_index';
   }
}

ضبط البيانات القابلة للبحث

سيحافظ نموذج toArray بشكل افتراضي لنموذج معين على فهرس البحث الخاص به. إذا رغبت في تخصيص البيانات التي تُزامن إلى فهرس البحث، فيمكنك إعادة تعريف التابع toSearchableArray في النموذج:

<?php

namespace App;

use Laravel\Scout\Searchable;

use Illuminate\Database\Eloquent\Model;

class Post extends Model

{
   use Searchable;

   /**
    * جلب مصفوفة البيانات القابلة للفهرسة بالنموذج     *
    * @إعادة مصفوفة     */

   public function toSearchableArray()
   {
       $array = $this->toArray();
      // Customize array...
       return $array;
   }
}

ضبط معرف النموذج

بشكل افتراضي، سيستعمل Scout المفتاح الأساسي للنموذج كمعرّف فريد يخزّن في فهرس البحث. إذا كنت تحتاج إلى تخصيص هذا السلوك، فيمكنك إعادة تعريف التابع getScoutKey في النموذج:

<?php

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
   use Searchable;

   /**
    * جلب القيمة المستعملة في فهرسة النموذج     *
    * @إعادة mixed     */

   public function getScoutKey()
   {
       return $this->email;
   }
}

الفهرسة

استيراد العديد من السجلات دفعةً واحدة

إذا كنت تثبت Scout في مشروع موجود، فقد يكون لديك بالفعل سجلات قاعدة البيانات تحتاج إلى استدعائها في برنامج تشغيل بحثك، يوفّر Scout أمر import Artisan الذي يمكنك استخدامه لاستيراد جميع السجلات الموجودة في فهارس البحث الخاصة بك:

php artisan scout:import "App\Post"

يمكنك استخدام أمر flush لإزالة جميع السجلات لنموذج من فهارس البحث الخاصة بك:

php artisan scout:flush "App\Post"

إضافة سجلات

بمجرد إضافة سمة Laravel\Scout\Searchable إلى نموذج، كل ما عليك فعله هو حفظ (save) نسخة من النموذج وستضاف تلقائيًا إلى فهرس البحث الخاصة بك. وإذا ضبطت Scout لاستخدام الطوابير، فستعمل هذه العملية في الخلفية عن طريق عامل الطابور:

$order = new App\Order;

// ...

$order->save();

إضافة عن طريق الاستعلام

إذا كنت ترغب في إضافة مجموعة من النماذج إلى فهرس البحث عبر استعلام Eloquent، فيمكنك ربط التابع searchable في استعلام Eloquent، وسيعمل التابع searchable على تجميع نتائج الاستعلام وإضافتها إلى فهرس البحث. ومرّة أخرى، إذا ضبطت Scout لاستخدام الطابور، ستضاف جميع القطع المُشكَّلة (chunks) في الخلفية عن طريق العاملين في الطابور:

// الإضافة عن طريق استعلام Eloquent...

App\Order::where('price', '>', 100)->searchable();

// يمكنك إضافة السجلات عن طريق العلاقات...

$user->orders()->searchable();

// يمكنك إضافة السجلات عن طريق المجموعات...

$orders->searchable();

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

تحديث السجلات

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

$order = App\Order::find(1);

// تحديث الطلب...

$order->save();

يمكنك أيضًا استخدام التابع searchable في استعلام Eloquent لتحديث مجموعة من النماذج، وإذا لم تكن النماذج موجودة في فهرس البحث الخاصة بك، فستُنشئَ:

// التحديث عبر استعلام Eloquent...

App\Order::where('price', '>', 100)->searchable();

// يمكنك التحديث عن طريق العلاقات

$user->orders()->searchable();

// يمكنك التحديث عن طريق المجموعات...

$orders->searchable();

إزالة السجلات

لإزالة سجل من الفهرس، احذف النموذج من قاعدة البيانات. هكذا طريقة من الإزالة متوافقة مع النماذج المحذوفة بشكل ناعم:

$order = App\Order::find(1);

$order->delete();

إذا كنت لا ترغب في استرداد النموذج قبل حذف السجل، يمكنك استخدام التابع unsearchable على نسخة استعلام Eloquent أو مجموعة:

// الحذف عن طريق استعلام Eloquent...

App\Order::where('price', '>', 100)->unsearchable();

// يمكنك الحذف عن طريق العلاقات...

$user->orders()->unsearchable();

// يمكنك الحذف عن طريق المجموعات...

$orders->unsearchable();

الإيقاف المؤقت للفهرسة

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

App\Order::withoutSyncingToSearch(function () {

  // Perform model actions...

});

أمثلة نماذج قابلة للبحث تحت شروط معيّنة

قد تحتاج في بعض الأحيان إلى إنشاء نموذج قابل للبحث تحت شروط معيّنة. فعلى سبيل المثال، تخيّل أن لديك نموذج App\Post الذي قد يكون في إحدى الحالتين التاليتيّن: "draft" و "published"، وقد ترغب فقط بالسماح للمنشورات "published" أن تكون قابلة للبحث. لتحقيق ذلك، يمكنك تعريف التابع shouldBeSearchable في النموذج الخاص بك:

public function shouldBeSearchable()

{
   return $this->isPublished();
}

البحث

يمكنك البدء في البحث عن نموذج باستخدام التابع search الذي يقبل سلسلة نصيّة واحدة والتي يمكن أن تُستخدم للبحث عن النماذج، ويجب عليك ربط التابع get في استعلام البحث لاسترداد نماذج Eloquent التي تتطابق مع استعلام البحث المحدد:

$orders = App\Order::search('Star Trek')->get();

نظرًا لأن عمليات البحث الخاصة بـ Scout ترجع مجموعة من نماذج Eloquent، يمكنك حتى إرجاع النتائج مباشرةً من مسار (route) أو وحدة تحكم (controller) وستتحول تلقائيًا إلى JSON:

use Illuminate\Http\Request;

Route::get('/search', function (Request $request) {

   return App\Order::search($request->search)->get();

});

إذا كنت ترغب في الحصول على النتائج الخام قبل تحويلها إلى نماذج Eloquent، فيجب عليك استخدام التابع raw:

$orders = App\Order::search('Star Trek')->raw();

عادةً ما تُنفذ استعلامات البحث على فهرس محدد بواسطة التابع searchableAs الخاص بالنموذج. ومع ذلك، يمكنك استخدام التابع within لتحديد فهرس مخصص يجب البحث عنه بدلًا من ذلك:

$orders = App\Order::search('Star Trek')

   ->within('tv_shows_popularity_desc')

   ->get();

عبارات Where

يسمح لك Scout بإضافة عبارة "where" البسيطة إلى استعلامات البحث الخاصة بك.  تدعم هذه العبارة في الوقت الحالي فحوصات المساواة الرقميّة الأساسيّة، وهي مفيدة خصوصًا لتحديد نطاق طلبات البحث باستخدام المعرّف. ونظرًا لأن فهرس البحث ليس قاعدة بيانات علائقية، فإن عبارات "where" الأكثر تقدمًا غير مدعومة حاليًا:

$orders = App\Order::search('Star Trek')->where('user_id', 1)->get();

ترقيم الصفحات

بالإضافة إلى استرداد مجموعة من النماذج، يمكنك تقسيم صفحات نتائج البحث الخاصة بك باستخدام التابع paginate، وسيُرجع هذا التابع نسخة Paginator تمامًا كما لو كنت عيّنت استعلام Eloquent تقليدي وقسّمت نتائجه:

$orders = App\Order::search('Star Trek')->paginate();

يمكنك تحديد عدد النماذج المطلوب استرجاعها لكل صفحة بتمرير القيمة على أنها المعامل الأول إلى التابع paginate:

$orders = App\Order::search('Star Trek')->paginate(15);

بمجرّد استرداد النتائج، يمكنك عرض النتائج وتَصْيير (render) روابط الصفحة باستخدام Blade كما لو كنت قد عيّنت استعلام Eloquent تقليدي وقسّمت نتائجه:

<div class="container">
    @foreach ($orders as $order)
        {{ $order->price }}
    @endforeach
</div>

{{ $orders->links() }}

الحذف الناعم

إذا كانت النماذج التي فُهرست محذوفة بشكل ناعم وتحتاج إلى البحث عن النماذج المحذوفة بشكل ناعم، فعّل خيار soft_delete عن طريق وضع القيمة true في ملف الضبط config/scout.php:

'soft_delete' => true,

عندما يكون خيار الضبط يساوي القيمة true، فلن يحذف Scout النماذج المحذوفة بشكل ناعم من فهرس البحث. وبدلًا من ذلك، سيُعيّن الخاصية المخفيّة soft_deleted__ على السجل المفهرس.  يمكنك بعد ذلك استخدام التوابع withTrashed أو onlyTrashed لاسترداد السجلات المحذوفة بشكل ناعم عند البحث:

// ضم السجلات المحذوفة عند استرداد النتائج...

$orders = App\Order::withTrashed()->search('Star Trek')->get();

// ضم السجلات المحذوفة فقط عند استرداد النتائج...

$orders = App\Order::onlyTrashed()->search('Star Trek')->get();

عندما يُحذف نموذج بشكل دائم باستخدام forceDelete، سيُزيله Scout بشكل تلقائي من فهرس البحث.

محركات البحث المخصصة Custom engines

كتابة محرك البحث

إذا لم يناسب محرك بحث Scout احتياجاتك، فيمكنك كتابة محرك البحث الخاص بك وتسجيله مع Scout. يجب على محركك أن يمدّد الصنف المجرّد Laravel\Scout\Engines\Engine إذ يحتوي على سبع توابع يجب على محركك المخصص تنفيذها:

use Laravel\Scout\Builder;

abstract public function update($models);

abstract public function delete($models);

abstract public function search(Builder $builder);

abstract public function paginate(Builder $builder, $perPage, $page);

abstract public function mapIds($results);

abstract public function map($results, $model);

abstract public function getTotalCount($results);

قد تجد أنه من المفيد مراجعة تطبيقات هذه التوابع على الصنف Laravel\Scout\Engines\AlgoliaEngine، وسيوفّر هذا الصنف نقطة بداية جيّدة لتعلم كيفيّة تنفيذ كل من هذه الطرق في محرك البحث الخاص بك.

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

بمجرّد كتابة محرك البحث المخصص، يمكنك تسجيله مع Scout باستخدام التابع extend من مدير محرك بحث Scout، ويجب عليك استدعاء التابع extend من التابع boot من مقدّم الخدمة AppServiceProvider أو أي مقدّم خدمة آخر يستخدمه تطبيقك. فعلى سبيل المثال، إذا كنت قد كتبت MySqlSearchEngine، فيجب عليك تسجيله كما يلي:

use Laravel\Scout\EngineManager;

/**
* تمهيد خدمات أي تطبيق.
*
* @return void
*/

public function boot()

{
   resolve(EngineManager::class)->extend('mysql', function () {
       return new MySqlSearchEngine;
   });

}

بمجرّد تسجيل المحرك الخاص بك، يمكنك تحديده كمشغّل Scout الافتراضي في ملف الضبط config/scout.php الخاص بك.

'driver' => 'mysql',

مصادر: