定制 erikwang2013/webman-scout 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

erikwang2013/webman-scout

Composer 安装命令:

composer require erikwang2013/webman-scout

包简介

Scout-style full-text search for Webman, Laravel, ThinkPHP, and Hyperf (Eloquent models, multiple engines).

README 文档

README

Navigate (top): Top · Features · Framework support · Requirements · Installation · Framework-specific setup · Configuration · Model setup · Basic usage · Advanced builder · Artisan / Webman commands · Queues · Builder reference · References · License

Left navigation (outline)

webman-scout

Driver-based full-text search for Eloquent models, inspired by Laravel Scout and shopwwi/webman-scout. This fork adds time ranges, aggregations, OpenSearch, vector / geo helpers, and clearer multi-framework configuration.

Languages: this file is English (default). 简体中文

Features

  • Scout-like API for easy migration from Laravel Scout / shopwwi webman-scout
  • Engines: OpenSearch, Elasticsearch, Meilisearch, Typesense, Algolia, XunSearch, Database, Collection, Null
  • OpenSearch-first advanced queries: aggregations, facets, KNN, geo distance
  • Optional queue-driven indexing (Webman Redis Queue when available)
  • Index settings sync, soft deletes, chunked import

Framework support

Runtime integration targets applications that expose Laravel’s config() helper and an Illuminate container (app()), with Eloquent (Illuminate\Database\Eloquent\Model) models.

Framework Versions Notes
Webman 1.x / 2.x Default install: plugin config under config/plugin/erikwang2013/webman-scout/.
Laravel 7.x – 11.x Copy the plugin app.php array into config/scout.php (or config/erikwang2013.webman-scout.php) and set SCOUT_CONFIG_KEY (see below). Requires PHP 8.0+ (Laravel 7 on PHP 8 is supported in recent 7.x releases).
Hyperf 2.x – 3.x Use Hyperf’s config + DI; Hyperf\Database\Model is Eloquent-compatible. Map Scout options into config and set SCOUT_CONFIG_KEY if not using the Webman plugin path.
ThinkPHP 6.x / 8.x Use when the app loads Illuminate config / app() (e.g. hybrid setups or illuminate/database Eloquent models). Native think\Model is not wired to the Searchable trait; call engine APIs manually or use Eloquent models for indexed entities.

Composer requires illuminate/* ^7.0 – ^11.0 and symfony/console ^5.4 – ^7.0 so dependency resolution matches your framework stack.

Requirements

  • PHP ^8.0
  • Eloquent models for the Searchable trait
  • illuminate/bus, contracts, database, http, pagination, queue, support (versions aligned with your Laravel / Hyperf / ThinkPHP stack)

Installation

composer require erikwang2013/webman-scout

The Composer autoload files entry loads helpers.php, which defines app(), event(), and scout_config() when needed and registers EngineManager.

Webman

After install, run the plugin installer (copies config and queue consumers):

  • Config: config/plugin/erikwang2013/webman-scout/
  • Consumers: app/queue/redis/search/

Laravel / Hyperf / ThinkPHP (non-plugin layout)

  1. Copy the contents of src/config/plugin/erikwang2013/webman-scout/app.php into your application config, e.g. config/scout.php, returning the same associative array (keys: driver, prefix, opensearch, meilisearch, …).
  2. Set environment variable SCOUT_CONFIG_KEY=scout (no trailing dot) so lookups use config('scout.driver'), etc., instead of the Webman plugin path.
  3. Ensure your bootstrap registers Illuminate’s config repository and container so config() and app() resolve EngineManager and engine clients.

If SCOUT_CONFIG_KEY is unset, the package prefers config('plugin.erikwang2013.webman-scout.app') when that array exists; otherwise it tries scout or erikwang2013.webman-scout.

Framework-specific setup

The following sections assume composer require erikwang2013/webman-scout is already done.

Webman (1.x / 2.x)

  1. Enable the plugin in your Webman project (per Webman plugins) so that config/plugin/erikwang2013/webman-scout/ is published. If your stack runs the package Install step, it copies plugin config and queue consumers; otherwise copy from vendor/erikwang2013/webman-scout/src/config/plugin/erikwang2013/webman-scout/ into your project.
  2. Config lives at config/plugin/erikwang2013/webman-scout/app.php. You normally do not set SCOUT_CONFIG_KEY so scout_config() resolves this path automatically.
  3. Console: commands are registered via config/plugin/erikwang2013/webman-scout/command.php (e.g. php webman scout:import "App\\Model\\Product" — adjust namespace to your app).
  4. Models usually extend support\Model (Eloquent-based) and use Searchable.
  5. Queues (optional): install/configure webman/redis-queue, set 'queue' => true in Scout config, and run consumers under app/queue/redis/search/ (scout_make, scout_remove). If Redis Queue is missing or queue is false, indexing runs synchronously in the request/process.

Laravel (7.x – 11.x)

  1. Config file: add config/scout.php that returns the same structure as this package’s src/config/plugin/erikwang2013/webman-scout/app.php (keys: driver, prefix, opensearch, meilisearch, queue, …).

    • Avoid loading both laravel/scout and this package under the same config/scout.php unless you know how to separate them; this package is a standalone Scout-style implementation.
  2. Environment: in .env set SCOUT_CONFIG_KEY=scout so scout_config('driver') reads config('scout.driver').

  3. Container: helpers.php registers EngineManager (and Meilisearch client when installed) on the active app() container. If you bootstrap before Composer’s files autoload, register the same bindings in AppServiceProvider::register():

    $this->app->singleton(\Erikwang2013\WebmanScout\EngineManager::class, function ($app) {
        return new \Erikwang2013\WebmanScout\EngineManager($app);
    });
  4. Artisan commands: commands are Symfony Command classes with names like scout:import. Register them with the framework:

    • Laravel 10 and below — in app/Console/Kernel.php:

      protected $commands = [
          \Erikwang2013\WebmanScout\Command\ImportCommand::class,
          \Erikwang2013\WebmanScout\Command\FlushCommand::class,
          \Erikwang2013\WebmanScout\Command\IndexCommand::class,
          \Erikwang2013\WebmanScout\Command\DeleteIndexCommand::class,
          \Erikwang2013\WebmanScout\Command\DeleteAllIndexesCommand::class,
          \Erikwang2013\WebmanScout\Command\QueueImportCommand::class,
          \Erikwang2013\WebmanScout\Command\SyncIndexSettingsCommand::class,
      ];
    • Laravel 11+ — in bootstrap/app.php use ->withCommands([...]) with the same class list (see Laravel 11 structure).

  5. Models extend Illuminate\Database\Eloquent\Model (or your base model) and use Searchable.

  6. Queues: async indexing in this package is wired to Webman\RedisQueue when that class exists. On stock Laravel, keep 'queue' => false in Scout config so changes are applied synchronously, or implement your own pipeline (e.g. dispatch a Laravel job from model observers) using syncMakeSearchable / engine update() as a reference.

Hyperf (2.x – 3.x)

  1. Config: place the Scout array under a Hyperf config file, e.g. config/autoload/scout.php, returning the same keys as the package app.php. Set SCOUT_CONFIG_KEY=scout in the environment Hyperf reads (so config('scout') is the root array).
  2. config() / app(): Hyperf provides config(); ensure the Illuminate Container is the one returned by app() if you rely on package helpers.php, or bind EngineManager in a Hyperf ConfigProvider / dependency injection config pointing at your container bridge.
  3. Models: Hyperf\Database\Model is Eloquent-compatible — use Searchable the same way as on Laravel when the database component is configured.
  4. Console: register the same command classes as Laravel with Hyperf’s command system (or invoke Symfony Application with these commands in a custom entry script).
  5. Queues: same as Laravel — without Webman\RedisQueue, prefer queue => false or custom async jobs.

ThinkPHP (6.x / 8.x)

  1. Scope: the Searchable trait expects Eloquent (Illuminate\Database\Eloquent\Model) observers and collections. It does not attach to think\Model out of the box.
  2. When it works: projects that already use illuminate/database (or another stack) with real Eloquent models, or a bridge that exposes Laravel-style config() and app() with the Illuminate container, can follow the Laravel steps: Scout config file + SCOUT_CONFIG_KEY + EngineManager binding.
  3. Pure ThinkPHP models: index data by calling app(EngineManager::class)->engine() (or the concrete engine class) update / delete / search with arrays you build yourself, or maintain a thin Eloquent model mapped to the same table for search-only usage.
  4. Config: ThinkPHP’s config('scout.driver') works if you define config/scout.php (or the version your major version uses) with the same array shape as this package’s app.php.

Quick checklist

Step Webman Laravel Hyperf ThinkPHP (Eloquent/hybrid)
Scout config file config/plugin/.../app.php config/scout.php config/autoload/scout.php config/scout.php (or equivalent)
SCOUT_CONFIG_KEY Usually omit scout scout scout (if not using plugin path)
Console php webman scout:* php artisan scout:* (after registration) Hyperf command registration Per your console setup
Async indexing Redis Queue + consumers queue false or custom jobs queue false or custom jobs queue false or custom jobs

Configuration

All Scout options are read via scout_config('key'), which respects the resolved config root above.

Key Purpose
driver Default engine: opensearch, elasticsearch, meilisearch, typesense, algolia, database, collection, null, …
prefix Index name prefix
queue Enable async indexing (Webman Redis Queue when installed)
chunk.searchable / chunk.unsearchable Chunk sizes for bulk import/remove
soft_delete Keep soft-deleted rows in the index

OpenSearch example

'opensearch' => [
    'host' => getenv('OPENSEARCH_HTTP_HOST') ?: 'https://127.0.0.1:6205',
    'username' => getenv('OPENSEARCH_USERNAME') ?: 'admin',
    'password' => getenv('OPENSEARCH_PASSWORD') ?: 'admin',
    'prefix' => getenv('OPENSEARCH_INDEX_PREFIX') ?: '',
    'ssl_verification' => (bool) (getenv('OPENSEARCH_SSL_VERIFICATION') ?: false),
    'indices' => [
        'products' => [
            'settings' => [ /* ... */ ],
            'mappings' => [
                'properties' => [
                    'vector' => ['type' => 'knn_vector', 'dimension' => 1536],
                    'location' => ['type' => 'geo_point'],
                ],
            ],
        ],
    ],
],

Model setup

use Erikwang2013\WebmanScout\Searchable;
use support\Model; // Webman; use your Eloquent base otherwise

class Product extends Model
{
    use Searchable;

    public function searchableAs(): string
    {
        return 'products';
    }

    public function toSearchableArray(): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => $this->content,
            'price' => $this->price,
            'created_at' => $this->created_at?->timestamp,
            'location' => ['lat' => $this->lat, 'lon' => $this->lng],
            'vector' => $this->embedding ?? [],
        ];
    }

    public function searchableFields(): array
    {
        return ['title', 'content'];
    }
}

Basic usage

// Search
$products = Product::search('phone')->get();

$products = Product::search('phone', function ($builder) {
    $builder->where('status', 1);
})->get();

$paginator = Product::search('phone')->paginate(15);

Product::search('keyword')
    ->where('status', 1)
    ->whereIn('category_id', [1, 2, 3])
    ->orderBy('created_at', 'desc')
    ->limit(20)
    ->get();

// Indexing
$product->searchableSync();
$product->searchable();
$product->unsearchable();
Product::makeAllSearchable();
Product::removeAllFromSearch();

Product::withoutSyncingToSearch(function () {
    Product::query()->where('id', 1)->update(['title' => 'New title']);
});

Advanced builder (OpenSearch / Elasticsearch-oriented)

Product::search('')
    ->whereRange('created_at', ['gte' => 1609459200, 'lte' => 1640995200], true)
    ->whereRange('price', ['gte' => 100, 'lt' => 500])
    ->get();

Product::search('')
    ->whereGeoDistance('location', 31.23, 121.47, 10.0)
    ->get();

Product::search('')
    ->fulltextSearch('keyword', ['title', 'content'], ['operator' => 'and'])
    ->get();

Product::search('')
    ->orderByVectorSimilarity([0.1, -0.2 /* ... */], 'vector')
    ->get();

$builder = Product::search('keyword')
    ->aggregate('price_ranges', 'range', 'price', ['ranges' => [
        ['from' => 0, 'to' => 100],
        ['from' => 100, 'to' => 500],
    ]])
    ->facet('category_id', ['size' => 10]);

$results = $builder->get();
$aggregations = $builder->getAggregations();
$facets = $builder->getFacets();

$engine = app(\Erikwang2013\WebmanScout\EngineManager::class)->engine();
$engine->updateIndexMappings('products', [
    'properties' => [
        'new_field' => ['type' => 'keyword'],
    ],
]);

$builder = Product::search('keyword');
$builder->whereRange('created_at', $range)->get();
$builder->clearAdvancedConditions();

Artisan / Webman commands

On Webman, use php webman …. On Laravel, register the command classes (see Laravel under Framework-specific setup) and run php artisan scout:import, etc.

Command Description
php webman scout:import [Model] Full import; --chunk, --fresh
php webman scout:flush [Model] Clear model data from the index
php webman scout:delete-index [Model] Drop index for the model
php webman scout:index List / create indexes (engine-dependent)
php webman scout:queue-import Queue-based import
php webman scout:sync-index-settings Sync index settings
php webman scout:delete-all-indexes Delete all managed indexes (dangerous)

Use --help on each command for options.

Queues

With queue enabled, searchable() / unsearchable() dispatch to Webman Redis Queue when Webman\RedisQueue\Redis is available. Ensure consumers under app/queue/redis/search are running (e.g. scout_make, scout_remove).

Builder reference (extensions)

Method Description
whereRange($field, array $range, bool $inclusive = true) Range filter
whereGeoDistance($field, $lat, $lng, $radius) Geo distance
fulltextSearch($query, array $fields = [], array $options = []) Full-text
orderByVectorSimilarity(array $vector, ?string $vectorField = null) Vector sort
aggregate(...) / facet(...) Aggregations / facets
addResultProcessor(callable $processor) Post-process hits
getAggregations() / getFacets() Read facet/agg results
clearAdvancedConditions() Reset advanced state

Engines such as OpenSearch expose updateIndexMappings(string $index, array $mappings).

References

开源不易,欢迎支持

微信 支付宝
微信 支付宝

License

MIT

© erik erik@erik.xyz · https://erik.xyz

erikwang2013/webman-scout 适用场景与选型建议

erikwang2013/webman-scout 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 300 次下载、GitHub Stars 达 3, 最近一次更新时间为 2026 年 01 月 28 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「search」 「elasticsearch」 「laravel」 「opensearch」 「algolia」 「thinkphp」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 erikwang2013/webman-scout 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 erikwang2013/webman-scout 我们能提供哪些服务?
定制开发 / 二次开发

基于 erikwang2013/webman-scout 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 300
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 3
  • 点击次数: 31
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 3
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-01-28