Replies: 1 comment
-
Hey there! 👋 Since you didn’t receive a reply and I faced the same question, I wanted to share my solution. Although this question is a bit older, someone might encounter the same issue and find this answer helpful. I created a small service class with the bare minimum functionality to make it work (likely improvable, but functional). Essentially, it works just like the LaravelSignPadController but without the token and validation parts. Since the controller only validates the presence of variables, not their actual content, I’ve kept it the same. However, feel free to enhance it as needed. <?php
namespace App\Services;
use Creagia\LaravelSignPad\Actions\GenerateSignatureDocumentAction;
use Creagia\LaravelSignPad\Contracts\CanBeSigned;
use Creagia\LaravelSignPad\Contracts\ShouldGenerateSignatureDocument;
use Creagia\LaravelSignPad\Exceptions\ModelHasAlreadyBeenSigned;
use Creagia\LaravelSignPad\Signature;
use DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use InvalidArgumentException;
class SignatureService
{
/**
* Stores a signature for a given model that implements the CanBeSigned contract.
*
* @param CanBeSigned $model The model to be signed.
* @param string $sign The base64-encoded signature image.
*
* @throws ModelHasAlreadyBeenSigned If the model has already been signed.
*/
public function store(CanBeSigned $model, string $sign): Signature
{
if ($model->hasBeenSigned()) {
throw new ModelHasAlreadyBeenSigned;
}
return DB::transaction(fn () => $this->processSignature($model, $sign));
}
/**
* Processes the signature by creating a signature record, saving the image,
* and optionally generating a signed document.
*
* @param CanBeSigned $model The model being signed.
* @param string $sign The base64-encoded signature image.
*/
private function processSignature(CanBeSigned $model, string $sign): Signature
{
$uuid = Str::uuid()->toString();
$signature = $this->createSignature($model, $uuid);
$decodedImage = $this->decodeBase64Image($sign);
$this->storeSignatureImage($signature, $decodedImage);
if ($model instanceof ShouldGenerateSignatureDocument) {
$this->generateSignatureDocument($signature, $model, $decodedImage);
}
return $signature->refresh();
}
/**
* Creates a signature record associated with the given model.
*
* @param CanBeSigned $model The model being signed.
* @param string $uuid A unique identifier for the signature.
* @return Signature The created signature record.
*/
private function createSignature(CanBeSigned $model, string $uuid): Signature
{
return $model->signature()->create([
'uuid' => $uuid,
'from_ips' => request()->ips(),
'filename' => "$uuid.png",
'certified' => config('sign-pad.certify_documents'),
]);
}
/**
* Stores the signature image on the configured disk.
*
* @param Signature $signature The signature record.
* @param string $imageData The binary data of the decoded image.
*/
private function storeSignatureImage(Signature $signature, string $imageData): void
{
$path = $signature->getSignatureImagePath();
$disk = config('sign-pad.disk_name');
Storage::disk($disk)->put($path, $imageData);
}
/**
* Generates a signed document based on a provided template and stores it.
*
* @param Signature $signature The signature record.
* @param ShouldGenerateSignatureDocument $model The model providing the template for the document.
* @param string $imageData The binary data of the signature image.
*/
private function generateSignatureDocument(Signature $signature, ShouldGenerateSignatureDocument $model, string $imageData): void
{
$template = $model->getSignatureDocumentTemplate();
$generateSignatureDocumentAction = app(GenerateSignatureDocumentAction::class);
$generateSignatureDocumentAction($signature, $template, $imageData);
}
/**
* Decodes a base64-encoded image string and validates its format.
*
* @param string $base64Image The base64-encoded image string.
* @return string The binary data of the decoded image.
*
* @throws InvalidArgumentException If the base64 string is not a valid image format or cannot be decoded.
*/
private function decodeBase64Image(string $base64Image): string
{
if (! str_starts_with($base64Image, 'data:image/')) {
throw new InvalidArgumentException('Invalid base64 image format.');
}
$imageParts = explode(',', $base64Image);
if (count($imageParts) !== 2) {
throw new InvalidArgumentException('Invalid base64 image format.');
}
$decodedImage = base64_decode($imageParts[1], true);
if ($decodedImage === false) {
throw new InvalidArgumentException('Invalid Base64 encoding.');
}
return $decodedImage;
}
} Since the original component isn’t fully compatible with Livewire, you’ll need to either include a slightly modified version of it or create a new component. We don’t use wire:click to call our function because the Base64 content of the signature is only set after clicking the button. By using $wire.call and setting the content via AlpineJS, we can ensure the signature content is properly set. (if not, try wapping it with $nextTick) <div class="e-signpad" data-disabled-without-signature="1">
<canvas style="touch-action: none; border: 1px solid #eaeaea; max-width: 100%"
width="600"
height="200"
class=""></canvas>
<div>
<input type="hidden" name="sign" x-ref="sign" class="sign">
<button type="button" class="sign-pad-button-clear">Clear</button>
<button @click="$wire.call('myLivewireComponentFunction', $refs.sign.value)" class="sign-pad-button-submit" disabled>
Save
</button>
</div>
</div> In your Livewire component, you can simply utilize dependency injection to retrieve the service and call the store method to generate a signature. public function myLivewireComponentFunction(string $sign, SignatureService $service): void
{
$signature = $service->store($this->myModel, $sign);
} Hope this helps. |
Beta Was this translation helpful? Give feedback.
-
Hi
Is there a trick to make this work in a livewire component ?
Beta Was this translation helpful? Give feedback.
All reactions