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 (4)
You deserve a star on github. I find it very useful.
thank you!
It's game changer for manage template.
Can it be translated? Otherwise it makes unusable in most scenarios...