40%

DISCOUNT

Use BLACKFRIDAY2022 coupon to get 40% discount on anything.

Only 7 purchases left with this discount. Promo expires 2 days from now.

40%

DISCOUNT

How to create a custom operation that uses Backpack fields

In previous articles, I've shown you how to: create an operation (EmailOperation) with a custom HTML form; use that operation on yo...

Karan Datwani
Karan Datwani
Share:

In previous articles, I've shown you how to:

But... what about if we want a custom form... to re-use Backpack fields? It's super-useful sometimes to just use select2, repeatable, daterange_picker, etc.

Good news: we can use the power of the 50+ fields Backpack offers. But... how do you do that? It's not that difficult actually... Here's how we can create the same EmailOperation we've created before, but this time using Backpack fields, not a custom HTML form.

So if we want our admin to send email... what do we need? We need:

  1. a Button for each user, that opens a form. We place it as an action in the list view;

  2. a Form with subject & message fields submitting to an endpoint;

  3. an Endpoint that takes in the form request, validates it and sends the email.

Steps

Step 1. Create Email Operation

First of all, we need a custom operation, to integrate with Backpack’s routes & user interface.

If you've installed backpack/generators, you can generate an empty operation trait using php artisan backpack:crud-operation Email

Here we will add the two routes in setupEmailRoutes() and two methods as follows:

  1. Get route calling getEmailForm() to show the form.
  2. Post route calling postEmailForm() to process submit request.
// app/Http/Controllers/Admin/Operations/EmailOperation.php
    
protected function setupEmailRoutes($segment, $routeName, $controller){
-    Route::get($segment . '/email', [
+    Route::get($segment . '/{id}/email', [
+        'as'        => $routeName . '.email',
-        'uses'      => $controller.'@email',
+        'uses'      => $controller . '@getEmailForm',
+        'operation' => 'email',
+    ]);
+    Route::post($segment . '/email/send/{id}', [
+        'as'        => $routeName . '.email-send',
+        'uses'      => $controller . '@postEmailForm',
+        'operation' => 'email',
+    ]);
}    
+
+ public function getEmailForm() {}
+
+ public function postEmailForm() {}

Step 2. Use it on your CrudController

In this example, I'm using EmailOperation inside UserCrudController. If you're the one that created UserCrudController, it should be as simple as:

    use \App\Http\Controllers\Admin\Operations\EmailOperation;

If not, and you're using PermissionManager's UserCrudController, click here to see how to take control of its UserCrudController.

Step 3. Create Email Button

We need a button to display inside the list view, so let's create it:

If you've installed backpack/generators, you can generate an empty operation trait using: php artisan backpack:button email

// resources/views/vendor/backpack/crud/buttons/email.blade.php
@if ($crud->hasAccess('email'))
  <a href="{{ url($crud->route.'/'.$entry->getKey().'/email') }}" class="btn btn-sm btn-link text-capitalize"><i class="la la-envelope"></i> email</a>
@endif

Then let's use it inside the EmailOperation.php we've created in the first step:

protected function setupEmailDefaults(){
        $this->crud->allowAccess('email');
        
        $this->crud->operation('email', function () {
            $this->crud->loadDefaultOperationSettingsFromConfig();
        });
        
        $this->crud->operation('list', function () {
            // $this->crud->addButton('top', 'email', 'view', 'crud::buttons.email');
-           // $this->crud->addButton('line', 'email', 'view', 'crud::buttons.email');
+           $this->crud->addButton('line', 'email', 'view', 'crud::buttons.email');
        });
}

Step 4. Setup Email Form

Let's copy the Create View from Backpack: php artisan backpack:publish crud/create

Then rename the created file from create.blade.php to email_form.blade.php, more specifically it'd be: /resources/views/vendor/backpack/crud/email_form.blade.php

The only change needed in this file is Form's POST Method URL as follows:

-<form method="post" action="{{ url($crud->route) }}">
+<form method="post" action="{{ url($crud->route.'/email/send/'.$entry->getKey()) }}">

Attention! Backpack crud views load some configurations from the config file, so let's duplicate the create config file and use it in our own operation. Just copy-paste and rename config/backpack/operations/create.php to config/backpack/operations/email.php

Now we'll define getEmailForm() to show the email form:

public function getEmailForm(){
    $this->crud->hasAccessOrFail('email');

    $this->crud->setHeading('Send Email');
    $this->crud->setSubHeading('Sending email to ' . backpack_user()->name);

    $this->data['crud'] = $this->crud;
    $this->data['entry'] = $this->crud->getCurrentEntry();
    $this->data['saveAction'] = $this->crud->getSaveAction();
    $this->data['title'] = "Send email to " . backpack_user()->name;

    return view('crud::email_form', $this->data);
}

At this point, we have our email form... but no fields... so let's add Backpack fields to the form and the save action button inside a new setupEmailOperation() (similar to what we normally do for the Create operation):

protected function setupEmailOperation(){
        $this->crud->addField([
            'name' => 'from',
            'type' => 'text',
            'value' => config('mail.from.address'),
            'wrapper' => [
                'class' => 'form-group col-md-4',
            ],
            'validationRules' => 'required|email'
        ]);
        $this->crud->addField([
            'name' => 'to',
            'type' => 'text',
            'value' => $this->crud->getCurrentEntry()->email,
            'attributes' => [
                'readonly'    => 'readonly',
                'disabled'    => 'disabled',
            ],
            'wrapper' => [
                'class' => 'form-group col-md-4',
            ],
        ]);
        $this->crud->addField([
            'name' => 'reply_to',
            'type' => 'text',
            'value' => backpack_user()->email,
            'wrapper' => [
                'class' => 'form-group col-md-4',
            ],
            'validationRules' => 'nullable|email'
        ]);
        $this->crud->addField([
            'name' => 'subject',
            'type' => 'text',
            'validationRules' => 'required|min:5',
        ]);
        $this->crud->addField([
            'name' => 'message',
            'type' => 'textarea',
            'validationRules' => 'required|min:5',
        ]);
        $this->crud->addSaveAction([
            'name' => 'send_email',
            'redirect' => function ($crud, $request, $itemId) {
                return $crud->route;
            },
            'button_text' => 'Send Email',
        ]);
    }

Now let's define postEmailForm() to validate and process form submission:

use Illuminate\Support\Facades\Mail;
use Prologue\Alerts\Facades\Alert;
use Exception;

public function postEmailForm(){
    $this->crud->hasAccessOrFail('email');
    $request = $this->crud->validateRequest();

    $entry = $this->crud->getCurrentEntry();
    try {
        // send the actual email
        Mail::raw($request['message'], function ($message) use ($entry, $request) {
            $message->from($request->from);
            $message->replyTo($request->reply_to);
            $message->to($entry->email, $entry->name);
            $message->subject($request['subject']);
        });

        Alert::success('Mail Sent')->flash();

        return redirect(url($this->crud->route));
    } catch (Exception $e) {
        // show a bubble with the error message
        Alert::error("Error, " . $e->getMessage())->flash();

        return redirect()->back()->withInput();
    }
}

Result

That's it, here's what we're getting from the above:

You can find the final code of this example here in this gist.

Summary

We learnt about the flexibility of Backpack and created a custom email action... that can use ANY Backpack field. We can use the same principles to define an SMS operation, for example. I hope it was helpful 😀

Let us know what you think in the comments below. Or tell us about something cool you've have built, at [email protected]

Want to receive more articles like this?

Subscribe to our "Article Digest". We'll send you a list of the new articles, every week, month or quarter - your choice.

Reactions & Comments

What do you think about this?

Latest Articles

Wondering what our community has been up to?