Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Text Formatter Laravel Package

s9e/text-formatter

PHP text formatting library with plugin support for BBCode, Markdown, HTML, and more. Includes predefined bundles, extensive documentation, and a JavaScript port for client-side preview and demos. Install via Composer and integrate customizable parsing/rendering.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel

  1. Installation

    composer require s9e/text-formatter
    
  2. Basic Usage

    use s9e\TextFormatter\TextFormatter;
    
    $formatter = new TextFormatter();
    $html = $formatter->parse('[b]Hello[/b]!');
    // Output: <strong>Hello</strong>!
    
  3. First Use Case: Comment System

    $configurator = new \s9e\TextFormatter\Configurator();
    $configurator->BBCodes; // Enable BBCodes by default
    $configurator->Autolink; // Auto-convert URLs
    $configurator->Smiley;   // Enable emoticons
    
    extract($configurator->finalize());
    $comment = "[b]Important[/b]! Don't forget to :smile:";
    $html = $renderer->render($parser->parse($comment));
    

Where to Look First


Implementation Patterns

1. Configurator-Based Workflows

Use the Configurator to define reusable formatting rules:

// Reusable config for forum posts
$forumConfigurator = new \s9e\TextFormatter\Configurator();
$forumConfigurator->BBCodes;
$forumConfigurator->Autolink;
$forumConfigurator->Smiley;
$forumConfigurator->Embed->setProvider('youtube', 'https://www.youtube.com/embed/{ID}?autoplay=0');

// Apply URL restrictions
$forumConfigurator->urlConfig->restrictHost('trusted-domain.com');

// Store for later use (e.g., in a service container)
app()->singleton('forum.formatter', function () use ($forumConfigurator) {
    extract($forumConfigurator->finalize());
    return $renderer;
});

2. Dynamic Plugin Activation

Enable plugins conditionally (e.g., based on user roles):

$configurator = new \s9e\TextFormatter\Configurator();
$user = auth()->user();

if ($user->can('use_markdown')) {
    $configurator->Fatdown; // Markdown + BBCodes
} else {
    $configurator->BBCodes;
}

if ($user->is_admin()) {
    $configurator->Embed; // Only admins get embeds
}

3. Custom BBCode Integration

Extend with domain-specific BBCode (e.g., for a wiki):

$configurator = new \s9e\TextFormatter\Configurator();
$configurator->BBCodes->addCustom(
    '[wiki page={TEXT}]', // Syntax: [wiki page="User_Guide"]
    '<a href="/wiki/{@page}" class="wiki-link">{@page}</a>'
);

// Add a filter to sanitize wiki page names
$configurator->tags['wiki']->attributes['page']->filterChain->append('strtolower');
$configurator->tags['wiki']->attributes['page']->filterChain->append('preg_replace("/[^a-z0-9_]/", "_", $attrValue)');

4. URL Sanitization Patterns

Restrict links/images by context (e.g., blog vs. comments):

// Blog post config (allow external links)
$blogConfigurator = new \s9e\TextFormatter\Configurator();
$blogConfigurator->Autolink;

// Comment config (restrict to whitelisted domains)
$commentConfigurator = new \s9e\TextFormatter\Configurator();
$commentConfigurator->Autolink;
$commentConfigurator->urlConfig->restrictHost('trusted-site.com');

5. Real-Time Preview with JavaScript

Pair with the JS port for client-side previews:

// In your Blade template
<script src="https://cdn.jsdelivr.net/npm/s9e-textformatter@latest/dist/s9e.textformatter.min.js"></script>
<script>
    const formatter = new s9e.TextFormatter();
    formatter.bundle('fatdown'); // Load Markdown + BBCodes
    document.getElementById('preview').innerHTML = formatter.parse(document.getElementById('input').value);
</script>

Gotchas and Tips

1. Performance Pitfalls

  • Avoid Overloading Plugins: Each plugin adds parsing overhead. Disable unused plugins (e.g., Embed if unused).
  • Cache Configurations: Reuse Configurator instances and cache parsed results:
    $cacheKey = md5($text . serialize($configurator->getPlugins()));
    return Cache::remember($cacheKey, 3600, function () use ($parser, $renderer, $text) {
        return $renderer->render($parser->parse($text));
    });
    

2. Debugging Tips

  • Enable Logging:
    $configurator->logger = new \s9e\TextFormatter\Logger\FileLogger('/path/to/logs');
    
  • Validate XML Output: Use DOMDocument to check parsed XML:
    $xml = $parser->parse('[b]Test[/b]');
    $dom = new DOMDocument();
    $dom->loadXML($xml);
    if ($dom->schemaValidate('path/to/schema.xsd')) { /* ... */ }
    

3. Common Quirks

  • URL Filtering Edge Cases:
    • Wildcards (*) in disallowHost match substrings, not subdomains. Use disallowHost('*.example.com') for subdomains.
    • restrictHost does not validate HTTPS/HTTP schemes by default (configure via allowScheme).
  • BBCode Attribute Conflicts: If two BBCode tags use the same attribute name (e.g., class), the last defined wins. Use unique names or filters to resolve conflicts.
  • Nested Tags: Some plugins (e.g., Embed) may not handle nested BBCode well. Test combinations thoroughly.

4. Extension Points

  • Custom Filters: Use filterChain->append() to modify attributes/tags dynamically:
    // Truncate long URLs in links
    $configurator->tags['a']->attributes['href']->filterChain->append(
        'strlen($attrValue) > 50 ? substr($attrValue, 0, 47) . "..." : $attrValue'
    );
    
  • Tag Validation: Invalidate tags based on business logic:
    $configurator->tags['alert']->filterChain[] = function ($tag) {
        if (!auth()->user()->can('see_alerts')) {
            $tag->invalidate();
        }
    };
    
  • Post-Processing: Use Renderer events to modify HTML output:
    $renderer->on('render', function ($html) {
        return str_replace('<strong>', '<b class="highlight">', $html);
    });
    

5. Security Considerations

  • Sanitize User Input: Always escape output when rendering HTML:
    echo e($renderer->render($parser->parse($userInput)));
    
  • Whitelist Domains: Restrict URLs/images to trusted sources:
    $configurator->urlConfig->restrictHost('cdn.yourdomain.com');
    $configurator->urlConfig->disallowScheme('javascript');
    
  • Disable Dangerous Plugins: Avoid enabling HTML or PHP plugins in user-generated content.

6. Laravel-Specific Tips

  • Service Provider Integration:
    // app/Providers/AppServiceProvider.php
    public function register()
    {
        $this->app->bind(\s9e\TextFormatter\TextFormatter::class, function () {
            $configurator = new \s9e\TextFormatter\Configurator();
            $configurator->BBCodes;
            $configurator->Autolink;
            extract($configurator->finalize());
            return new \s9e\TextFormatter\TextFormatter($parser, $renderer);
        });
    }
    
  • Eloquent Observers: Auto-format fields on save:
    // app/Observers/PostObserver.php
    public function saving(Post $post)
    {
        $formatter = app(\s9e\TextFormatter\TextFormatter::class);
        $post->content = $formatter->parse($post->content);
    }
    
  • Form Request Validation: Validate BBCode syntax:
    // app/Http/Requests/StorePostRequest.php
    public function rules()
    {
        return [
            'content' => 'required|s9e_textformatter', // Custom rule
        ];
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui