$args * @return self|null Null for arguments this plugin did not write. */ public static function fromArgs(array $args): ?self { $leadId = (string) ($args['lead'] ?? ''); $destinationId = (string) ($args['destination'] ?? ''); if (!Ulid::isOne($leadId) || !Ulid::isOne($destinationId)) { return null; } return new self($leadId, $destinationId, max(1, (int) ($args['attempt'] ?? 1)), (string) ($args['submission'] ?? 'primary')); } /** * @return array{lead: string, destination: string, attempt: int, submission: string} */ public function toArgs(): array { return ['lead' => $this->leadId, 'destination' => $this->destinationId, 'attempt' => $this->attempt, 'submission' => $this->submissionId]; } /** @param list|null $delays A type's own schedule; null for the default. */ public function hasAttemptsLeft(?array $delays = null): bool { return $this->attempt < ($delays === null ? self::MAX_ATTEMPTS : count($delays) + 1); } public function next(): self { return new self($this->leadId, $this->destinationId, $this->attempt + 1, $this->submissionId); } /** * How long before the next attempt — the type's own delay for the attempt * just made, or exponential where it declares none. * * @param list|null $delays */ public function backoffSeconds(?array $delays = null): int { return $delays[$this->attempt - 1] ?? self::BACKOFF_SECONDS * (2 ** ($this->attempt - 1)); } }