如何实现Laravel Blade自定义函数无需传入$model即可调用
Great question! I've been in this exact situation before—wanting to eliminate those repetitive old('title') ? old('title') : $model->title checks without having to pass the model to every helper call. Here are two reliable approaches to make {{ decide('title') }} work seamlessly:
Approach 1: Update Your Helper Function to Auto-Detect the Model
The key here is to let your helper pull the model directly from the current view's data. To make this work, you'll first need to standardize the variable name you use for your model in controllers (e.g., always pass $model to create/edit views).
Step 1: Standardize Controller Model Variable
In your create and edit controller methods, pass the model with a consistent name:
// Edit method public function edit($id) { $model = Post::findOrFail($id); return view('posts.edit', compact('model')); } // Create method public function create() { $model = new Post(); // Empty model for create form return view('posts.create', compact('model')); }
Step 2: Modify the Helper Function
Update your decide function in app/helpers.php to fetch the model from the view's data:
function decide($inputName) { // Get all data available to the current view (shared + local) $viewData = app('view')->shared() + app('view')->getFacadeRoot()->getData(); // Fetch the standardized model variable $model = $viewData['model'] ?? null; if (!$model) { throw new \Exception("No 'model' variable found in the view. Ensure you pass a model using the variable name 'model'."); } // Use null coalescing operator for cleaner syntax return old($inputName) ?? $model->$inputName; }
Now you can call {{ decide('title') }} in your Blade views without passing the model!
Approach 2: Create a Custom Blade Directive
If you prefer Blade-native syntax over helper functions, a custom directive is a great alternative. It automatically has access to the view's variable context, so you can skip passing the model entirely (again, with a standardized variable name).
Step 1: Register the Blade Directive
Add this to the boot method of your App\Providers\AppServiceProvider:
use Illuminate\Support\Facades\Blade; public function boot() { Blade::directive('decide', function ($inputName) { // The $inputName will be a quoted string (e.g., 'title'), so we can use it directly return "<?php echo old($inputName) ?? \$model->$inputName; ?>"; }); }
Step 2: Use It in Your Views
In your Blade forms, replace the helper call with the directive:
<input type="text" name="title" value="@decide('title')">
This works exactly like the helper method, but uses Blade's native syntax.
Bonus: Make the Directive Flexible
If you sometimes use different variable names for your model (e.g., $post instead of $model), modify the directive to accept an optional model variable name:
Blade::directive('decide', function ($expression) { // Parse the input expression to extract parameters $params = explode(',', str_replace(['(', ')', '\'', '"'], '', $expression)); $inputName = trim($params[0]); $modelVar = trim($params[1] ?? 'model'); return "<?php echo old('{$inputName}') ?? \${$modelVar}->{$inputName}; ?>"; });
Now you can use the default @decide('title') or specify a custom model variable: @decide('title', 'post').
Both approaches eliminate the need to pass the model to every value check, keeping your Blade views clean and concise.
内容的提问来源于stack exchange,提问作者DominikN.

