Serialize only the subscriber primary key to avoid ModelNotFound on unserialize when the row is gone. Guard handle() when subscriberId is missing after old payload shapes. Made-with: Cursor
195 lines
6.2 KiB
PHP
195 lines
6.2 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Jobs;
|
||
|
||
use App\Models\MailwizzConfig;
|
||
use App\Models\Subscriber;
|
||
use App\Services\MailwizzCheckboxlistTags;
|
||
use App\Services\MailwizzService;
|
||
use App\Services\MailwizzSubscriberFormPayload;
|
||
use Illuminate\Bus\Queueable;
|
||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
|
||
use Illuminate\Foundation\Bus\Dispatchable;
|
||
use Illuminate\Queue\InteractsWithQueue;
|
||
use Illuminate\Support\Facades\Log;
|
||
use RuntimeException;
|
||
use Throwable;
|
||
|
||
class SyncSubscriberToMailwizz implements ShouldBeUnique, ShouldQueueAfterCommit
|
||
{
|
||
use Dispatchable;
|
||
use InteractsWithQueue;
|
||
use Queueable;
|
||
|
||
/**
|
||
* Seconds before the unique lock expires if the worker dies before releasing it.
|
||
*/
|
||
public int $uniqueFor = 86400;
|
||
|
||
public int $tries = 3;
|
||
|
||
/**
|
||
* @var list<int>
|
||
*/
|
||
public array $backoff = [10, 30, 60];
|
||
|
||
/**
|
||
* Set in the constructor for new jobs. Remains null when an old queue payload (pre–subscriber-id refactor) is unserialized.
|
||
*/
|
||
public ?int $subscriberId = null;
|
||
|
||
/**
|
||
* @param Subscriber|int $subscriber Model is accepted when dispatching; only the id is serialized for the queue.
|
||
*/
|
||
public function __construct(Subscriber|int $subscriber)
|
||
{
|
||
$this->subscriberId = $subscriber instanceof Subscriber
|
||
? (int) $subscriber->getKey()
|
||
: $subscriber;
|
||
$this->onQueue('mailwizz');
|
||
}
|
||
|
||
public function uniqueId(): string
|
||
{
|
||
return $this->subscriberId !== null
|
||
? (string) $this->subscriberId
|
||
: 'stale-mailwizz-sync-payload';
|
||
}
|
||
|
||
public function handle(): void
|
||
{
|
||
if ($this->subscriberId === null) {
|
||
Log::notice('SyncSubscriberToMailwizz: skipped job with missing subscriber id (stale queue payload). Clear the queue or re-dispatch sync jobs.');
|
||
|
||
return;
|
||
}
|
||
|
||
try {
|
||
$this->runSync();
|
||
} catch (Throwable $e) {
|
||
Log::error('SyncSubscriberToMailwizz: integration failed; subscriber remains local (use admin resync if needed)', [
|
||
'subscriber_id' => $this->subscriberId,
|
||
'message' => $e->getMessage(),
|
||
]);
|
||
}
|
||
}
|
||
|
||
private function runSync(): void
|
||
{
|
||
$subscriber = Subscriber::query()
|
||
->with(['preregistrationPage.mailwizzConfig'])
|
||
->find($this->subscriberId);
|
||
|
||
if ($subscriber === null) {
|
||
return;
|
||
}
|
||
|
||
$page = $subscriber->preregistrationPage;
|
||
$config = $page?->mailwizzConfig;
|
||
|
||
if ($page === null || $config === null) {
|
||
return;
|
||
}
|
||
|
||
if (! $this->configIsComplete($config)) {
|
||
Log::warning('SyncSubscriberToMailwizz: incomplete Mailwizz config', [
|
||
'subscriber_id' => $subscriber->id,
|
||
'page_id' => $page->id,
|
||
]);
|
||
$this->fail(new RuntimeException('Incomplete Mailwizz configuration.'));
|
||
|
||
return;
|
||
}
|
||
|
||
$apiKey = $config->api_key;
|
||
if (! is_string($apiKey) || $apiKey === '') {
|
||
Log::warning('SyncSubscriberToMailwizz: missing API key', ['subscriber_id' => $subscriber->id]);
|
||
$this->fail(new RuntimeException('Mailwizz API key is missing.'));
|
||
|
||
return;
|
||
}
|
||
|
||
$service = new MailwizzService($apiKey);
|
||
$listUid = $config->list_uid;
|
||
|
||
$search = $service->searchSubscriber($listUid, $subscriber->email);
|
||
|
||
if ($search === null) {
|
||
$this->createInMailwizz($service, $subscriber, $config, $listUid);
|
||
} else {
|
||
$this->updateInMailwizz($service, $subscriber, $config, $listUid, $search['subscriber_uid']);
|
||
}
|
||
|
||
$subscriber->update([
|
||
'synced_to_mailwizz' => true,
|
||
'synced_at' => now(),
|
||
]);
|
||
}
|
||
|
||
public function failed(?Throwable $exception): void
|
||
{
|
||
Log::error('SyncSubscriberToMailwizz failed', [
|
||
'subscriber_id' => $this->subscriberId,
|
||
'message' => $exception?->getMessage(),
|
||
]);
|
||
}
|
||
|
||
private function configIsComplete(MailwizzConfig $config): bool
|
||
{
|
||
if ($config->list_uid === '' || $config->field_email === '' || $config->field_first_name === '' || $config->field_last_name === '') {
|
||
return false;
|
||
}
|
||
|
||
if ($config->tag_field === null || $config->tag_field === '' || $config->tag_value === null || $config->tag_value === '') {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
private function createInMailwizz(
|
||
MailwizzService $service,
|
||
Subscriber $subscriber,
|
||
MailwizzConfig $config,
|
||
string $listUid
|
||
): void {
|
||
$page = $subscriber->preregistrationPage;
|
||
$data = MailwizzSubscriberFormPayload::baseFields($subscriber, $config, $page->isPhoneFieldEnabledForSubscribers());
|
||
$tagField = $config->tag_field;
|
||
$tagValue = $config->tag_value;
|
||
if ($tagField !== null && $tagField !== '' && $tagValue !== null && $tagValue !== '') {
|
||
$data[$tagField] = [$tagValue];
|
||
}
|
||
|
||
$service->createSubscriber($listUid, $data);
|
||
}
|
||
|
||
private function updateInMailwizz(
|
||
MailwizzService $service,
|
||
Subscriber $subscriber,
|
||
MailwizzConfig $config,
|
||
string $listUid,
|
||
string $subscriberUid
|
||
): void {
|
||
$page = $subscriber->preregistrationPage;
|
||
$data = MailwizzSubscriberFormPayload::baseFields($subscriber, $config, $page->isPhoneFieldEnabledForSubscribers());
|
||
|
||
$tagField = $config->tag_field;
|
||
$tagValue = $config->tag_value;
|
||
if ($tagField !== null && $tagField !== '' && $tagValue !== null && $tagValue !== '') {
|
||
$full = $service->getSubscriber($listUid, $subscriberUid);
|
||
if ($full === null) {
|
||
throw new RuntimeException('Mailwizz getSubscriber returned an empty payload.');
|
||
}
|
||
$existingCsv = MailwizzCheckboxlistTags::extractCsvFromSubscriberResponse($full, $tagField);
|
||
$merged = MailwizzCheckboxlistTags::mergeValueIntoCsv($existingCsv, $tagValue);
|
||
$data[$tagField] = $merged;
|
||
}
|
||
|
||
$service->updateSubscriber($listUid, $subscriberUid, $data);
|
||
}
|
||
}
|