voku/stop-words
PHP library providing curated stop-word lists for many languages (e.g., en, de, fr, es, ru, ar). Simple API to fetch stop words by language code, useful for search, indexing, and text processing pipelines.
composer require voku/stop-words
First Use Case: Filter stop words from a text string in English within a Laravel controller:
use Voku\StopWords\StopWords;
class SearchController extends Controller
{
public function search(Request $request)
{
$query = $request->input('q');
$stopWords = new StopWords('en');
$filteredQuery = $stopWords->filter($query);
// Use $filteredQuery for search logic (e.g., Scout, Algolia, or DB query)
return SearchResult::where('content', 'like', "%{$filteredQuery}%")->get();
}
}
Where to Look First:
StopWords class: Core functionality for filtering.getAvailableLanguages(): List of supported languages (e.g., 'en', 'de', 'es').filter() method: Primary method for removing stop words from text.Pattern: Register StopWords as a Laravel singleton in a service provider.
// app/Providers/AppServiceProvider.php
use Voku\StopWords\StopWords;
public function register()
{
$this->app->singleton(StopWords::class, function ($app) {
return new StopWords(config('app.locale')); // Default to app locale
});
}
Usage:
// In any controller/service
$stopWords = app(StopWords::class);
$filteredText = $stopWords->filter("The quick brown fox");
Pattern: Use middleware to filter stop words from incoming requests (e.g., search queries).
// app/Http/Middleware/FilterStopWords.php
public function handle($request, Closure $next)
{
if ($request->has('q')) {
$stopWords = app(StopWords::class);
$request->merge(['q' => $stopWords->filter($request->input('q'))]);
}
return $next($request);
}
Register in app/Http/Kernel.php:
protected $middleware = [
\App\Http\Middleware\FilterStopWords::class,
];
Pattern: Automatically filter stop words when saving user-generated content (e.g., blog posts).
// app/Observers/PostObserver.php
use Voku\StopWords\StopWords;
class PostObserver
{
public function saving(Post $post)
{
$stopWords = new StopWords('en'); // Or inject via DI
$post->content = $stopWords->filter($post->content);
}
}
Register in Post model:
protected static function booted()
{
static::observe(PostObserver::class);
}
Pattern: Select stop-word language based on user locale or request.
// In a controller or service
$locale = app()->getLocale(); // Laravel's current locale
$stopWords = new StopWords($locale);
$filteredText = $stopWords->filter($request->input('content'));
Pattern: Override stop words for specific models (e.g., exclude "bank" for finance apps).
// app/Services/TextProcessor.php
use Voku\StopWords\StopWords;
class TextProcessor
{
public function filterForModel($text, $modelClass)
{
$stopWords = new StopWords('en');
if ($modelClass === Post::class) {
$stopWords->addStopWords(['custom', 'terms']); // Model-specific exclusions
}
return $stopWords->filter($text);
}
}
Pattern: Process large datasets asynchronously (e.g., cleaning old comments).
// app/Jobs/ProcessCommentsJob.php
use Voku\StopWords\StopWords;
class ProcessCommentsJob implements ShouldQueue
{
public function handle()
{
$stopWords = new StopWords('en');
Comment::chunk(100, function ($comments) use ($stopWords) {
foreach ($comments as $comment) {
$comment->update([
'content' => $stopWords->filter($comment->content)
]);
}
});
}
}
Dispatch the job:
ProcessCommentsJob::dispatch();
Pattern: Filter stop words before indexing searchable content.
// app/Models/Post.php
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
public function toSearchableArray()
{
$stopWords = app(StopWords::class);
return [
'title' => $stopWords->filter($this->title),
'content' => $stopWords->filter($this->content),
];
}
}
Pattern: Filter stop words from API responses (e.g., search results).
// app/Http/Controllers/SearchController.php
public function index(Request $request)
{
$results = SearchModel::search($request->input('q'));
$stopWords = app(StopWords::class);
return response()->json(
array_map(function ($result) use ($stopWords) {
return [
'title' => $stopWords->filter($result->title),
'excerpt' => $stopWords->filter($result->excerpt),
];
}, $results)
);
}
Case Sensitivity:
$stopWords->filter(strtolower($text));
Punctuation Handling:
Str::of($text)->lower()->words() or preg_replace to clean text first:
use Illuminate\Support\Str;
$cleanText = Str::of($text)->lower()->words()->implode(' ');
$filtered = $stopWords->filter($cleanText);
Language Mismatches:
if (!in_array($locale, $stopWords->getAvailableLanguages())) {
throw new \InvalidArgumentException("Unsupported language: {$locale}");
}
Performance with Large Texts:
$chunkSize = 5000;
$chunks = array_chunk(str_word_count($text, 1), $chunkSize);
$filteredChunks = array_map(fn($chunk) => $stopWords->filter(implode(' ', $chunk)), $chunks);
$filteredText = implode(' ', $filteredChunks);
Default Language Fallback:
$stopWords = new StopWords('en'); // Always specify
Inspect Stop-Word Lists:
logger()->debug('Stop words for English:', $stopWords->getStopWords('en'));
Test Edge Cases:
$stopWords->filter(""); // Should return ""
$stopWords->filter("Café au lait"); // May not handle non-Latin scripts well
Validate Filtered Output:
$filtered = $stopWords->filter("The bank is open");
$this->assertNotContains("bank", $filtered); // If "bank" should not be filtered
Memory Usage:
$memoryBefore = memory_get_usage();
$filtered = $stopWords->filter($largeText);
$memoryAfter = memory_get_usage();
logger()->debug("Memory used: " . ($memoryAfter - $memoryBefore) . " bytes");
Language Codes:
'en' for English, 'de' for German). Check getAvailableLanguages() for the full list.Custom Stop-Word Files:
$stopWords = new StopWords('en');
$stopWords->setStopWords(['custom', 'list', 'here']);
Caching:
How can I help you explore Laravel packages today?