becklyn/search-text-transformer
Converts HTML into clean, searchable plain text for indexing with search engines like Elasticsearch. Use SearchTextTransformer to strip tags and normalize content, making page text suitable for full‑text search and highlighting.
Installation:
composer require becklyn/search-text-transformer
Add to composer.json if using a monorepo or custom package.
First Use Case: Transform a simple HTML snippet in a Laravel controller or service:
use Becklyn\SearchText\SearchTextTransformer;
$transformer = new SearchTextTransformer();
$cleanText = $transformer->transform("<p>Hello, <strong>world</strong>!</p>");
// Output: "Hello, world!"
Where to Look First:
tests/fixtures/: Real-world examples of HTML-to-text transformations.SearchTextTransformer.php: Core logic and method signatures.Service Container Integration (Laravel): Bind the transformer to an interface for testability and dependency injection:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton(SearchTextTransformerInterface::class, function ($app) {
return new SearchTextTransformer();
});
}
Use in controllers/services:
use Illuminate\Support\Facades\App;
$transformer = App::make(SearchTextTransformerInterface::class);
$cleanText = $transformer->transform($htmlContent);
Facade for Convenience: Create a facade to simplify usage:
// app/Facades/SearchText.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class SearchText extends Facade
{
protected static function getFacadeAccessor()
{
return 'searchTextTransformer';
}
}
Register in AppServiceProvider:
$this->app->bind('searchTextTransformer', function ($app) {
return new SearchTextTransformer();
});
Usage:
use App\Facades\SearchText;
$cleanText = SearchText::transform($html);
Artisan Command for Batch Processing: Transform large datasets via CLI:
// app/Console/Commands/TransformSearchText.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Facades\SearchText;
class TransformSearchText extends Command
{
protected $signature = 'search:text-transform {--model= : Model to process}';
protected $description = 'Transform HTML content to searchable text';
public function handle()
{
$model = $this->option('model');
$records = $model::all();
foreach ($records as $record) {
$record->searchable_text = SearchText::transform($record->html_content);
$record->save();
}
$this->info("Transformed {$records->count()} records.");
}
}
Event Listeners for Real-Time Transformation: Hook into model events to transform content on-the-fly:
// app/Listeners/TransformHtmlContent.php
namespace App\Listeners;
use App\Facades\SearchText;
class TransformHtmlContent
{
public function handle($event)
{
$event->model->searchable_text = SearchText::transform($event->model->html_content);
}
}
Register in EventServiceProvider:
protected $listen = [
'eloquent.saved: App\Models\BlogPost' => [
'App\Listeners\TransformHtmlContent',
],
];
Elasticsearch Integration: Use the transformer in a custom ingest pipeline or application-side:
// Example: Pre-process before sending to Elasticsearch
$elasticClient = app('elasticsearch');
$blogPost = BlogPost::find(1);
$document = [
'title' => $blogPost->title,
'content' => SearchText::transform($blogPost->html_content),
'url' => route('blog.post', $blogPost),
];
$elasticClient->index('blog_posts', $blogPost->id, $document);
Batch Indexing Workflow:
* 3 * * * php artisan search:text-transform --model=BlogPost
Real-Time Search Workflow:
searchable_text column for fast queries.Hybrid Approach:
Testing:
tests/fixtures/blog_posts.test).--TEST--
Transform blog post HTML into searchable text.
--HTML--
<article>
<h1>Getting Started with Laravel</h1>
<p>Laravel is a <strong>PHP framework</strong>...</p>
</article>
--EXPECT--
Getting Started with Laravel
Laravel is a PHP framework...
Customization:
class CustomSearchTextTransformer extends SearchTextTransformer
{
public function transform($html)
{
$text = parent::transform($html);
// Add custom logic (e.g., preserve headings)
return $this->preserveHeadings($text);
}
protected function preserveHeadings($text)
{
// Custom implementation
return $text;
}
}
Performance:
$cacheKey = 'search_text_' . md5($html);
$cleanText = Cache::remember($cacheKey, now()->addHours(1), function () use ($html) {
return SearchText::transform($html);
});
Error Handling:
try {
return SearchText::transform($html);
} catch (\Exception $e) {
return strip_tags($html); // Fallback
}
Malformed HTML:
if (!libxml_use_internal_errors(true)) {
throw new \RuntimeException("Failed to validate HTML.");
}
$dom = new \DOMDocument();
$dom->loadHTML($html);
libxml_clear_errors();
Nested or Complex HTML:
DOMDocument for complex cases:
$dom = new \DOMDocument();
$dom->loadHTML($html);
$text = '';
foreach ($dom->getElementsByTagName('body') as $node) {
$text .= $this->nodeToText($node);
}
Scripts and Styles:
Performance with Large Datasets:
BlogPost::chunk(100, function ($posts) {
foreach ($posts as $post) {
$post->searchable_text = SearchText::transform($post->html_content);
}
BlogPost::whereIn('id', $posts->pluck('id'))->update(['searchable_text' => \DB::raw('searchable_text')]);
});
Last Release (2022):
Log Raw and Transformed Text: Add debug logging to inspect transformations:
\Log::debug('Raw HTML:', ['html' => $html]);
$cleanText = SearchText::transform($html);
\Log::debug('Transformed Text:', ['text' => $cleanText]);
Test Edge Cases: Use the package’s test format to validate transformations:
--HTML--
<div><script>alert('test');</script><p>Content</p></div>
--EXPECT--
Content
Profile Performance: Benchmark transformation time for large HTML payloads:
$start = microtime(true);
$cleanText = SearchText::transform($largeHtml);
$time = microtime(true) - $start;
\Log::info("Transformation time: {$time}s");
How can I help you explore Laravel packages today?