Building Dynamic Documents Content with Placeholdify
Nasrul Hazim Bin Mohamad

Nasrul Hazim Bin Mohamad @nasrulhazim

About: Solution Architect & Software Engineer

Location:
Malaysia
Joined:
Nov 29, 2017

Building Dynamic Documents Content with Placeholdify

Publish Date: Oct 16
1 4

Building dynamic documents in Laravel applications has always been a challenge. Whether you're generating invoices, certificates, official letters, or personalized emails, managing template placeholders can quickly become a nightmare of string concatenation and conditional logic.

Today, I'm excited to introduce Placeholdify - a powerful Laravel package that transforms how you work with dynamic templates, making placeholder replacement elegant, maintainable, and developer-friendly.

The Problem with Traditional Template Systems

Before diving into what makes Placeholdify special, let's acknowledge the pain points developers face with traditional approaches:

// The old way - messy and error-prone
$template = "Dear {{name}}, your invoice #{{invoice_no}} for {{amount}} is due on {{due_date}}";
$content = str_replace(['{{name}}', '{{invoice_no}}', '{{amount}}', '{{due_date}}'], 
                      [$user->name, $invoice->number, '$' . number_format($invoice->total, 2), $invoice->due_date->format('F j, Y')], 
                      $template);
Enter fullscreen mode Exit fullscreen mode

This approach quickly becomes unwieldy when you need:

  • Date formatting
  • Currency conversion
  • Conditional content
  • Nested object properties
  • Fallback values
  • Reusable template logic

Enter Placeholdify: Template Replacement Reimagined

Placeholdify is a zero-dependency Laravel package that provides a fluent, powerful API for managing dynamic templates. Here's the same example, reimagined:

use CleaniqueCoders\Placeholdify\PlaceholderHandler;

$template = "Dear {name}, your invoice #{invoice_no} for {amount} is due on {due_date}";

$content = (new PlaceholderHandler())
    ->add('name', $user->name)
    ->add('invoice_no', $invoice->number)
    ->addFormatted('amount', $invoice->total, 'currency', 'USD')
    ->addDate('due_date', $invoice->due_date, 'F j, Y')
    ->replace($template);
Enter fullscreen mode Exit fullscreen mode

Clean, readable, and maintainable. But this is just the beginning.

Key Features That Set Placeholdify Apart

1. Context-Aware Mapping

One of Placeholdify's most powerful features is context mapping. Instead of manually extracting properties from objects every time, you can register reusable mappings:

$handler = new PlaceholderHandler();

// Register once
$handler->registerContextMapping('user', [
    'name' => 'full_name',
    'email' => 'email_address',
    'role' => 'roles.0.name', // Supports dot notation
    'company' => fn($user) => $user->company->name ?? 'Freelancer',
]);

// Use anywhere
$handler->useContext('user', $currentUser, 'user');
// This automatically maps: {user_name}, {user_email}, {user_role}, {user_company}
Enter fullscreen mode Exit fullscreen mode

2. Built-in Formatters with Custom Support

Placeholdify comes with powerful built-in formatters for common scenarios:

$handler
    ->addFormatted('price', 1234.56, 'currency', 'MYR') // RM1,234.56
    ->addFormatted('size', 1048576, 'filesize') // 1.00 MB
    ->addFormatted('count', 5, 'number', 2) // 5.00
    ->addDate('created', $model->created_at, 'd/m/Y') // 15/10/2024
    ->addFormatted('status', 'active', 'upper'); // ACTIVE
Enter fullscreen mode Exit fullscreen mode

Need custom formatting? Create your own formatter:

use CleaniqueCoders\Placeholdify\Contracts\FormatterInterface;

class PhoneFormatter implements FormatterInterface
{
    public function getName(): string
    {
        return 'phone';
    }

    public function format($value, ...$options): string
    {
        // Format Malaysian phone numbers
        $cleaned = preg_replace('/\D/', '', $value);
        return preg_replace('/(\d{3})(\d{3})(\d{4})/', '$1-$2-$3', $cleaned);
    }
}

$handler->registerFormatter(new PhoneFormatter());
$handler->addFormatted('contact', '0123456789', 'phone'); // 012-345-6789
Enter fullscreen mode Exit fullscreen mode

3. Lazy Evaluation for Performance

For expensive operations, Placeholdify supports lazy evaluation:

$handler->addLazy('expensive_calculation', function() use ($model) {
    // This only runs if the placeholder is actually used in the template
    return $model->complexCalculation();
});
Enter fullscreen mode Exit fullscreen mode

4. Template Modifiers (Inline Formatting)

Use inline modifiers for quick formatting without pre-processing:

$template = "Hello {name|upper}, your balance is {amount|currency:USD}";
// Works directly without additional setup
Enter fullscreen mode Exit fullscreen mode

5. Dedicated Template Classes

For complex scenarios, create dedicated template classes:

namespace App\Services\Templates;

use CleaniqueCoders\Placeholdify\PlaceholdifyBase;

class InvoiceTemplate extends PlaceholdifyBase
{
    protected function configure(): void
    {
        $this->handler->setFallback('N/A');

        $this->handler->registerContextMapping('customer', [
            'name' => 'company_name',
            'address' => 'billing_address',
            'tax_id' => 'tax_identification',
        ]);
    }

    public function build($invoice): PlaceholderHandler
    {
        return $this->handler
            ->add('invoice_no', $invoice->number)
            ->addDate('date', $invoice->created_at, 'F j, Y')
            ->addDate('due_date', $invoice->due_date, 'F j, Y')
            ->addFormatted('subtotal', $invoice->subtotal, 'currency', 'USD')
            ->addFormatted('tax', $invoice->tax_amount, 'currency', 'USD')
            ->addFormatted('total', $invoice->total, 'currency', 'USD')
            ->useContext('customer', $invoice->customer, 'customer');
    }
}

// Usage
$template = new InvoiceTemplate();
$content = $template->build($invoice)->replace($invoiceTemplate);
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

Academic Institution Management

Placeholdify shines in educational institutions where various documents need dynamic generation:

// Student permit system
class PermitTemplate extends PlaceholdifyBase
{
    public function build($application): PlaceholderHandler
    {
        return $this->handler
            ->add('permit_no', $this->generatePermitNumber($application))
            ->addDate('issued_date', now(), 'F j, Y')
            ->addDate('expiry_date', now()->addYear(), 'F j, Y')
            ->useContext('student', $application->student, 'student')
            ->useContext('appliance', $application->appliance, 'appliance')
            ->add('room_no', $application->room_number)
            ->add('approved_by', $application->approvedBy->name);
    }
}
Enter fullscreen mode Exit fullscreen mode

E-commerce and Invoice Generation

Perfect for generating dynamic invoices, receipts, and order confirmations:

$handler = new PlaceholderHandler();
$content = $handler
    ->add('order_id', $order->id)
    ->addDate('order_date', $order->created_at, 'd/m/Y')
    ->addFormatted('total', $order->total, 'currency', 'USD')
    ->useContext('customer', $order->customer, 'customer')
    ->useContext('shipping', $order->shippingAddress, 'shipping')
    ->replace($orderTemplate);
Enter fullscreen mode Exit fullscreen mode

Legal Document Generation

Generate contracts, agreements, and legal notices:

class ContractTemplate extends PlaceholdifyBase
{
    public function build($contract): PlaceholderHandler
    {
        return $this->handler
            ->add('contract_no', $contract->number)
            ->addDate('start_date', $contract->start_date, 'F j, Y')
            ->addDate('end_date', $contract->end_date, 'F j, Y')
            ->addFormatted('monthly_rent', $contract->monthly_rent, 'currency', 'USD')
            ->useContext('tenant', $contract->tenant, 'tenant')
            ->useContext('landlord', $contract->landlord, 'landlord')
            ->useContext('property', $contract->property, 'property');
    }
}
Enter fullscreen mode Exit fullscreen mode

Installation and Getting Started

Getting started with Placeholdify is incredibly simple:

composer require cleaniquecoders/placeholdify
Enter fullscreen mode Exit fullscreen mode

Optionally, publish the configuration file:

php artisan vendor:publish --tag=placeholdify-config
Enter fullscreen mode Exit fullscreen mode

The basic usage couldn't be simpler:

use CleaniqueCoders\Placeholdify\PlaceholderHandler;

// Quick static method
$content = PlaceholderHandler::process($template, [
    'name' => 'John Doe',
    'amount' => '$99.99'
]);

// Or use the fluent API for more control
$handler = new PlaceholderHandler();
$content = $handler
    ->add('name', 'John Doe')
    ->addFormatted('amount', 99.99, 'currency', 'USD')
    ->replace($template);
Enter fullscreen mode Exit fullscreen mode

Advanced Configuration

Placeholdify offers extensive configuration options:

// config/placeholdify.php
return [
    'delimiter' => [
        'start' => '{',
        'end' => '}',
    ],
    'fallback' => 'N/A',
    'formatters' => [
        // Register global formatters
    ],
    'contexts' => [
        // Register global contexts
    ],
];
Enter fullscreen mode Exit fullscreen mode

You can also customize delimiters per instance:

$handler->setDelimiter('{{', '}}'); // Use {{ }} instead of { }
$handler->setDelimiter('[[]]'); // Use [[ ]] for both start and end
Enter fullscreen mode Exit fullscreen mode

Artisan Commands

Placeholdify includes a helpful Artisan command to boost your productivity:

# Generate a new template class
php artisan make:placeholder InvoiceTemplate template

# Generate a new context class
php artisan make:placeholder UserContext context

# Generate a new formatter class
php artisan make:placeholder PhoneFormatter formatter

# List all available component types
php artisan make:placeholder --list
Enter fullscreen mode Exit fullscreen mode

Conclusion

Placeholdify represents a significant evolution in how Laravel developers can handle dynamic template generation. By providing a fluent API, powerful formatting options, context mapping, and extensible architecture, it eliminates the friction and complexity traditionally associated with placeholder replacement.

Whether you're building a simple email system or a complex document generation platform, Placeholdify scales to meet your needs while keeping your code clean, maintainable, and testable.

The package is production-ready, well-tested, and designed to integrate seamlessly with existing Laravel applications. With zero dependencies and comprehensive documentation, there's never been a better time to upgrade your template handling.

Get Started Today

Ready to transform your template handling? Install Placeholdify today:

composer require cleaniquecoders/placeholdify
Enter fullscreen mode Exit fullscreen mode

Visit the GitHub repository for documentation, examples, and community support.


Photo by Luke Chesser on Unsplash

Comments 4 total

  • peppelauro
    peppelauroOct 19, 2025

    You deserve a star on github. I find it very useful.

  • viral shah
    viral shahOct 19, 2025

    It's game changer for manage template.

  • Stas
    StasNov 14, 2025

    Can it be translated? Otherwise it makes unusable in most scenarios...

Add comment