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

Util Interpolator Laravel Package

phrity/util-interpolator

Lightweight PHP string interpolation helper. Replaces {key} tokens with values from an array/object, supports nested paths (default “.” separator, customizable), and can be used via Interpolator class or InterpolatorTrait. Uses Phrity Accessor/Transformer.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require phrity/util-interpolator
    
  2. Basic Usage:

    use Phrity\Util\Interpolator\Interpolator;
    
    $interpolator = new Interpolator();
    $result = $interpolator->interpolate('Hello, {name}!', ['name' => 'John']);
    // Output: "Hello, John!"
    
  3. First Laravel Use Case:

    • Dynamic Email Templates: Replace hardcoded values in email templates with user-specific data.
      $template = "Welcome, {user.name}! Your verification link: {verification.url}";
      $data = [
          'user' => ['name' => 'Jane Doe'],
          'verification' => ['url' => url('/verify-email')]
      ];
      $personalizedEmail = $interpolator->interpolate($template, $data);
      

Implementation Patterns

Common Workflows

1. Template Rendering in Controllers

public function showWelcome(Interpolator $interpolator, User $user)
{
    $template = "Hi {user.name}, your balance is {user.balance}.";
    $rendered = $interpolator->interpolate($template, ['user' => $user->toArray()]);
    return view('welcome', ['content' => $rendered]);
}

2. Service Layer Integration

  • Dynamic Configuration:
    class NotificationService {
        public function __construct(private Interpolator $interpolator) {}
    
        public function sendWelcomeEmail(User $user) {
            $template = file_get_contents(storage_path('templates/welcome.txt'));
            $data = ['user' => $user->toArray()];
            $message = $this->interpolator->interpolate($template, $data);
            Mail::send([], [], fn() => new Message($message));
        }
    }
    

3. Trait Usage in Models

class User extends Model {
    use InterpolatorTrait;

    public function getGreeting(): string {
        return $this->interpolate(
            'Welcome, {first_name}! Your ID is {id}.',
            $this->attributes
        );
    }
}

4. Custom Path Separators for APIs

$interpolator = new Interpolator(separator: '/');
$apiResponse = $interpolator->interpolate(
    'Status: {response/data/status}',
    ['response' => json_decode(file_get_contents('api_response.json'), true)]
);

5. Value Transformation

  • JSON Data Handling:
    $transformer = new Phrity\Util\Transformer\JsonDecoder();
    $interpolator = new Interpolator(transformer: $transformer);
    $result = $interpolator->interpolate(
        'User: {user.name}, Posts: {user.posts.length}',
        ['user' => '{"name": "Alice", "posts": [1, 2, 3]}']
    );
    // Output: "User: Alice, Posts: 3"
    

Integration Tips

Laravel Service Provider Binding

public function register()
{
    $this->app->bind(Interpolator::class, function ($app) {
        return new Interpolator(
            transformer: new Phrity\Util\Transformer\FirstMatchResolver([
                new Phrity\Util\Transformer\ReadableConverter(),
                new Phrity\Util\Transformer\BasicTypeConverter(),
            ])
        );
    });
}

Blade Directives for Templating

// In a service provider
Blade::directive('interpolate', function ($expression) {
    return "<?php echo app(\\Phrity\\Util\\Interpolator\\Interpolator::class)->interpolate($expression[0], $expression[1]); ?>";
});

// Usage in Blade
@interpolate('Hello, {name}!', ['name' => $user->name])

Dynamic Template Loading

public function renderTemplate(string $templatePath, array $data): string
{
    $template = file_get_contents(resource_path("views/templates/{$templatePath}.txt"));
    return $this->interpolator->interpolate($template, $data);
}

Gotchas and Tips

Pitfalls

  1. Path Resolution Failures:

    • Issue: Nested paths like {user.address.city} will fail if intermediate keys (e.g., address) are missing.
    • Fix: Use Phrity\Util\Accessor\SafeAccessor to handle missing keys gracefully.
      $interpolator = new Interpolator(accessor: new SafeAccessor());
      $result = $interpolator->interpolate('City: {user.address.city}', ['user' => ['name' => 'Bob']]);
      // Output: "City: "
      
  2. Circular References:

    • Issue: Deeply nested or circular data structures (e.g., user->posts->author->posts) may cause stack overflows.
    • Fix: Limit recursion depth or flatten data before interpolation.
  3. Transformer Conflicts:

    • Issue: Custom transformers might override expected behavior (e.g., converting null to an empty string).
    • Fix: Extend FirstMatchResolver to prioritize your transformers.
      $transformer = new FirstMatchResolver([
          new NullToEmptyStringTransformer(), // Custom
          new ReadableConverter(),
      ]);
      
  4. Performance with Large Templates:

    • Issue: Repeated interpolation on large strings (e.g., HTML emails) can be slow.
    • Fix: Cache interpolated results or pre-compile templates.
      $cached = Cache::remember("template_{$user->id}", now()->addHours(1), fn() =>
          $interpolator->interpolate($template, $data)
      );
      
  5. Security:

    • Issue: Arbitrary path access (e.g., {user.__proto__}) could expose sensitive data.
    • Fix: Whitelist allowed paths or use a restricted accessor.
      $allowedPaths = ['user.name', 'user.email'];
      $accessor = new AllowedPathsAccessor($allowedPaths);
      

Debugging Tips

  1. Enable Verbose Logging:

    $interpolator = new Interpolator(accessor: new DebugAccessor());
    // Logs all attempted path accesses to storage/logs/debug.log
    
  2. Validate Input Data:

    $data = $this->validateData($replacers);
    $result = $interpolator->interpolate($template, $data);
    
    private function validateData(array $data): array {
        foreach ($data as $key => $value) {
            if (is_array($value) && empty($value)) {
                throw new \InvalidArgumentException("Empty array for key: {$key}");
            }
        }
        return $data;
    }
    
  3. Test Edge Cases:

    $testCases = [
        ['{missing}', [], ''], // Missing key
        ['{user.name}', ['user' => null], ''], // Null value
        ['{0}', [0 => 'zero'], 'zero'], // Numeric keys
        ['{{literal}}', [], '{literal}'], // Escaped braces
    ];
    

Extension Points

  1. Custom Accessor:

    • Extend Phrity\Util\Accessor\AccessorInterface to implement custom path resolution logic.
    • Example: Support for Laravel collections or Eloquent relationships.
      class EloquentAccessor implements AccessorInterface {
          public function access($data, string $path): mixed {
              return data_get($data, $path) ?? $data->{$path};
          }
      }
      
  2. Custom Transformers:

    • Add support for Laravel-specific types (e.g., Carbon, Collection).
      class CarbonTransformer implements TransformerInterface {
          public function transform($value): string {
              return $value->format('Y-m-d H:i:s');
          }
      }
      
  3. Interpolation Events:

    • Use Laravel events to log or modify interpolation results.
      event(new InterpolationPerformed($template, $data, $result));
      
  4. Fallback Values:

    • Extend the interpolator to support default values for missing keys.
      $result = $interpolator->interpolate('Name: {name|default}', ['name' => null], fallback: 'Guest');
      // Output: "Name: Guest"
      
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor