Aerendir/aws-ses-monitor-bundle

View on GitHub
src/Entity/Bounce.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php

declare(strict_types=1);

/*
 * This file is part of the Serendipity HQ Aws Ses Bundle.
 *
 * Copyright (c) Adamo Aerendir Crespi <aerendir@serendipityhq.com>.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace SerendipityHQ\Bundle\AwsSesMonitorBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * A Bounce Entity.
 *
 * @see http://docs.aws.amazon.com/ses/latest/DeveloperGuide/notification-contents.html#bounce-object
 *
 * @ORM\Table(name="shq_aws_ses_monitor_bounces")
 * @ORM\Entity()
 */
class Bounce
{
    /** Hard bounces and subtypes.
     * @var string */
    public const TYPE_PERMANENT = 'Permanent';

    /** @var string */
    public const TYPE_PERM_GENERAL = 'General';

    /** @var string */
    public const TYPE_PERM_NOEMAIL = 'NoEmail';

    /** @var string */
    public const TYPE_PERM_SUPPRESSED = 'Suppressed';

    /** Soft bunces and subtypes.
     * @var string */
    public const TYPE_TRANSIENT = 'Transient';

    /** @var string */
    public const TYPE_TRANS_GENERAL = 'General';

    /** @var string */
    public const TYPE_TRANS_BOXFULL = 'MailboxFull';

    /** @var string */
    public const TYPE_TRANS_TOOLARGE = 'MessageTooLarge';

    /** @var string */
    public const TYPE_TRANS_CONTREJECTED = 'ContentRejected';

    /** @var string */
    public const TYPE_TRANS_ATTACHREJECTED = 'AttachmentRejected';

    /** Undetermined bounces.
     * @var string */
    public const TYPE_UNDETERMINED = 'Undetermined';

    /** @var string */
    private const BOUNCE = 'bounce';

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer", unique=true)
     * @ORM\Id
     * @ORM\GeneratedValue()
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="EmailStatus", inversedBy="bounces", cascade={"persist"})
     * @ORM\JoinColumn(name="email_status", referencedColumnName="address")
     */
    private EmailStatus $emailStatus;

    /**
     * The MessageObject that reported this bounce.
     *
     * @ORM\ManyToOne(targetEntity="SerendipityHQ\Bundle\AwsSesMonitorBundle\Entity\MailMessage", inversedBy="bounces")
     * @ORM\JoinColumn(name="mail_message", referencedColumnName="message_id")
     */
    private MailMessage $mailMessage;

    /**
     * The date and time at which the bounce was sent (in ISO8601 format).
     *
     * Note that this is the time at which the notification was sent by the ISP, and not the time at which it was
     * received by Amazon SES.
     *
     * @ORM\Column(name="bounced_on", type="datetime")
     */
    private \DateTimeInterface $bouncedOn;

    /** @ORM\Column(name="type", type="string") */
    private string $type;

    /** @ORM\Column(name="sub_type", type="string") */
    private string $subType;

    /**
     * A unique ID for the bounce.
     *
     * @ORM\Column(name="feedback_id", type="string")
     */
    private string $feedbackId;

    /**
     * The value of the Reporting-MTA field from the DSN.
     *
     * This is the value of the Message Transfer Authority (MTA) that attempted to perform the delivery, relay, or
     * gateway operation described in the DSN.
     *
     * @ORM\Column(name="reporting_mta", type="string", nullable=true)
     */
    private ?string $reportingMta = null;

    /**
     * The value of the Action field from the DSN.
     *
     * This indicates the action performed by the Reporting-MTA as a result of its attempt to deliver the message to
     * this recipient.
     *
     * @ORM\Column(name="action", type="text", nullable=true)
     */
    private ?string $action = null;

    /**
     * The value of the EmailStatus field from the DSN.
     *
     * This is the per-recipient transport-independent status code that indicates the delivery status of the message.
     *
     * @ORM\Column(name="status", type="string", nullable=true)
     */
    private ?string $status = null;

    /**
     * The status code issued by the reporting MTA.
     *
     * This is the value of the Diagnostic-Code field from the DSN. This field may be absent in the DSN (and therefore
     * also absent in the JSON).
     *
     * @ORM\Column(name="diagnostic_code", type="text", nullable=true)
     */
    private ?string $diagnosticCode = null;

    public static function create(EmailStatus $email, MailMessage $mailMessage, array $bouncedRecipient, array $notification): Bounce
    {
        $bounce = (new self())
            ->setBouncedOn(new \DateTime($notification[self::BOUNCE]['timestamp']))
            ->setType($notification[self::BOUNCE]['bounceType'])
            ->setSubType($notification[self::BOUNCE]['bounceSubType'])
            ->setFeedbackId($notification[self::BOUNCE]['feedbackId'])
            ->setMailMessage($mailMessage)
            ->setEmailStatus($email);

        if (isset($notification[self::BOUNCE]['reportingMta'])) {
            $bounce->setReportingMta($notification[self::BOUNCE]['reportingMta']);
        }

        if (isset($bouncedRecipient['action'])) {
            $bounce->setAction($bouncedRecipient['action']);
        }

        if (isset($bouncedRecipient['status'])) {
            $bounce->setStatus($bouncedRecipient['status']);
        }

        if (isset($bouncedRecipient['diagnosticCode'])) {
            $bounce->setDiagnosticCode($bouncedRecipient['diagnosticCode']);
        }

        return $bounce;
    }

    /**
     * @codeCoverageIgnore
     */
    public function getId(): int
    {
        return $this->id;
    }

    public function getEmailStatus(): EmailStatus
    {
        return $this->emailStatus;
    }

    public function getMailMessage(): MailMessage
    {
        return $this->mailMessage;
    }

    public function getBouncedOn(): \DateTimeInterface
    {
        return $this->bouncedOn;
    }

    public function getFeedbackId(): string
    {
        return $this->feedbackId;
    }

    public function getReportingMta(): ?string
    {
        return $this->reportingMta;
    }

    public function getAction(): ?string
    {
        return $this->action;
    }

    public function getStatus(): ?string
    {
        return $this->status;
    }

    public function getDiagnosticCode(): ?string
    {
        return $this->diagnosticCode;
    }

    public function getType(): string
    {
        return $this->type;
    }

    public function getSubType(): string
    {
        return $this->subType;
    }

    public function isPermanent(): bool
    {
        return self::TYPE_PERMANENT === $this->type;
    }

    private function setEmailStatus(EmailStatus $emailStatus): self
    {
        $this->emailStatus = $emailStatus;
        $emailStatus->addBounce($this);

        return $this;
    }

    private function setType(string $type): self
    {
        $this->type = $type;

        return $this;
    }

    private function setSubType(string $subType): self
    {
        $this->subType = $subType;

        return $this;
    }

    private function setFeedbackId(string $feedbackId): self
    {
        $this->feedbackId = $feedbackId;

        return $this;
    }

    private function setReportingMta(string $reportingMta): self
    {
        $this->reportingMta = $reportingMta;

        return $this;
    }

    private function setAction(string $action): self
    {
        $this->action = $action;

        return $this;
    }

    private function setStatus(string $status): self
    {
        $this->status = $status;

        return $this;
    }

    private function setDiagnosticCode(string $diagnosticCode): self
    {
        $this->diagnosticCode = $diagnosticCode;

        return $this;
    }

    private function setBouncedOn(\DateTimeInterface $bouncedOn): self
    {
        $this->bouncedOn = $bouncedOn;

        return $this;
    }

    private function setMailMessage(MailMessage $mailMessage): self
    {
        $this->mailMessage = $mailMessage;
        $this->mailMessage->addBounce($this);

        return $this;
    }
}