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);
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);
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}
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
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
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();
});
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
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);
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);
}
}
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);
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');
}
}
Installation and Getting Started
Getting started with Placeholdify is incredibly simple:
composer require cleaniquecoders/placeholdify
Optionally, publish the configuration file:
php artisan vendor:publish --tag=placeholdify-config
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);
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
],
];
You can also customize delimiters per instance:
$handler->setDelimiter('{{', '}}'); // Use {{ }} instead of { }
$handler->setDelimiter('[[]]'); // Use [[ ]] for both start and end
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
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
Visit the GitHub repository for documentation, examples, and community support.
Photo by Luke Chesser on Unsplash
Top comments (0)