bnomei/kirby3-mailjet

View on GitHub
classes/MailjetCampaignDraft.php

Summary

Maintainability
B
5 hrs
Test Coverage
<?php

declare(strict_types=1);

namespace Bnomei;

use DateTime;
use Exception;
use Kirby\Cms\Field;
use Mailjet\Client;
use Mailjet\Resources;

use function mailjet;

/**
 * @method setLocale(string $value): self
 * @method setSender(int $value): self
 * @method setSenderemail(string $value): self
 * @method setSubject(string $value): self
 * @method setTitle(string $value): self
 * @method setDatetime(DateTime $value): self
 * @method setTemplate(int $value): self
 * @method setText(string $value): self
 * @method setHtml(string $value): self
 * @method setUrl(string $value): self
 * @method setContactslist(int $value): self
 * @method setSegment(int $value): self
 * @method setCampaign(int $value): self
 * @method getLocale(): ?string
 * @method getSender(): ?int
 * @method getSenderemail(): ?string
 * @method getSubject(): ?string
 * @method getTitle(): ?string
 * @method getDatetime(): ?\Datetime
 * @method getTemplate(): ?int
 * @method getText(): ?string
 * @method getHtml(): ?string
 * @method getUrl(): ?string
 * @method getContactslist(): ?int
 * @method getSegment(): ?int
 * @method getCampaign(): ?int
 */
final class MailjetCampaignDraft
{
    /** @var Client */
    private $client;
    /** @var string|null */
    private $locale;
    /** @var string|null */
    private $sender;
    /** @var string */
    private $senderemail;
    /** @var string */
    private $subject;
    /** @var string */
    private $title;
    /** @var string */
    private $text;
    /** @var string */
    private $html;
    /** @var string */
    private $url;
    /** @var DateTime|null */
    private $datetime;
    /** @var int|null */
    private $template;
    /** @var int|null */
    private $segment;
    /** @var int|null */
    private $contactslist;
    /** @var int|null */
    private $campaign;

    public static $fluentProperties = [
        'locale',
        'sender',
        'senderemail',
        'subject',
        'title',
        'datetime',
        'template',
        'text',
        'html',
        'url',
        'contactslist',
        'segment',
        'campaign',
    ];
    /**
     * @var MailjetLog
     */
    private $log;

    public function __construct(Client $client, MailjetLog $log)
    {
        $this->client = $client;
        $this->log = $log;
    }

    public function __call(string $name, $arguments)
    {
        if (strlen($name) > 3 && strpos($name, 'get') === 0) {
            return $this->get($name);
        }

        if (strlen($name) > 3 && strpos($name, 'set') === 0 &&
            is_array($arguments) && count($arguments) === 1) {
            return $this->set($name, $arguments[0]);
        }
    }

    private function get(string $name)
    {
        $getters = array_map(static function ($item) {
            return 'get' . ucfirst($item);
        }, static::$fluentProperties);

        $key = array_search($name, $getters);
        if ($key !== false) {
            return $this->{static::$fluentProperties[$key]};
        } else {
            throw new Exception('Invalid getter: ' . $name);
        }
    }

    private function set(string $name, $value): self
    {
        $setters = array_map(static function ($item) {
            return 'set' . ucfirst($item);
        }, static::$fluentProperties);

        $key = array_search($name, $setters);
        if ($key !== false) {
            if (is_a($value, Field::class)) {
                $value = $value->value();
            }
            $this->{static::$fluentProperties[$key]} = $value;
        } else {
            throw new Exception('Invalid getter: ' . $name);
        }

        return $this;
    }

    public function id(): ?int
    {
        return $this->campaign;
    }

    public function saveDraft(): bool
    {
        $wasCreated = false;

        $campaign = $this->findDraft();
        if (is_null($campaign)) {
            $campaign = $this->createDraft();
            $wasCreated = true;
            if (is_null($campaign)) {
                return false;
            }
        }
        $this->campaign = $campaign;

        if (! $wasCreated) {
            $response = $this->client->put(Resources::$Campaigndraft, [
                'ID' => $this->campaign,
                'Body' => $this->bodyFull(),
            ]);
            // $this->log->write('saveDraft.put', 'info', $response->getData());
        }

        $response = $this->client->post(Resources::$CampaigndraftDetailcontent, [
            'ID' => $this->campaign,
            'Body' => $this->detailContent(),
        ]);
        // $this->log->write('saveDraft.detailcontent.post', 'info', $response->getData());

        return $response->success();
    }

    private function detailContent(): array
    {
        $detailContent = [
            'Text-part' => $this->text,
            'Html-part' => $this->html,
        ];
        return $detailContent;
    }

    private function bodyUnique(): array
    {
        $body = [
            'Locale' => $this->locale,      // required
            'Subject' => $this->subject,    // required
        ];
        if ($this->contactslist) {
            $body['Contactslist'] = $this->contactslist;
        }
        if ($this->segment) {
            $body['SegmentationID'] = $this->segment;
        }
        return $body;
    }

    public function bodyFull(): array
    {
        $body = [
            'Locale' => $this->locale,
            'Sender' => $this->sender,
            'SenderEmail' => $this->senderemail,
            'Subject' => $this->subject,
            'Title' => $this->title,
            'Url' => $this->url,
            'ContactsListID' => $this->contactslist,
            'SegmentationID' => $this->segment,
            'TemplateID' => $this->template,
        ];

        $body = array_filter($body, static function ($value) {
            return ! is_null($value) && strlen(trim(strval($value))) > 0;
        });
        $body = array_map(static function ($value) {
            return strval($value);
        }, $body);

        return $body;
    }

    private function findDraft(): ?int
    {
        if (! $this->locale || ! $this->subject) {
            return null;
        }

        $response = $this->client->get(Resources::$Campaigndraft, [
            'Filters' => $this->bodyUnique(),
        ]);
        //$this->log->write('findDraft', 'debug', $response->getData());

        return $response->success() && count($response->getData()) ?
            $response->getData()[0]['ID'] :
            null;
    }

    private function createDraft(): ?int
    {
        $response = $this->client->post(Resources::$Campaigndraft, [
            'Body' => $this->bodyFull(),
        ]);
        // $this->log->write('createDraft', 'debug', $response->getData());

        var_dump($response->getData());

        return $response->success() && count($response->getData()) ?
            $response->getData()[0]['ID'] :
            null;
    }

    public function status(): ?string
    {
        if (! $this->campaign) {
            return null;
        }

        $exists = $this->client->get(Resources::$CampaigndraftStatus, [
            'ID' => $this->campaign
        ]);

        return $exists->success() ? strtolower($exists->getData()[0]['Status']) : null;
    }

    public function statusSchedule(): ?string
    {
        if (! $this->campaign) {
            return null;
        }

        $exists = $this->client->get(Resources::$CampaigndraftSchedule, [
            'ID' => $this->campaign
        ]);

        return $exists->success() ? strtolower($exists->getData()[0]['Status']) : null;
    }

    public function test(string $email): bool
    {
        if (! $this->campaign) {
            return false;
        }

        $response = $this->client->post(Resources::$CampaigndraftTest, [
            'ID' => $this->campaign,
            'Body' => ['Recipients' => [['Email' => $email]]    ]
        ]);

        return $response->success() ? $response->getData()[0]['Status'] === 'draft' : false;
    }

    public function publish(): bool
    {
        return $this->send();
    }

    public function send(): bool
    {
        $response = $this->client->post(Resources::$CampaigndraftSend, [
            'ID' => $this->campaign
        ]);
        return $response->success() ? in_array($response->getData()[0]['Status'], ['programmed', 'sent']) : false;
    }

    public function schedule(): bool
    {
        if (! $this->campaign || ! $this->datetime) {
            return false;
        }
        $status = $this->statusSchedule();

        // new
        if (! $status) {
            $response = $this->client->post(Resources::$CampaigndraftSchedule, [
                'ID' => $this->campaign,
                'Body' => [
                    'Date' => substr(
                        $this->datetime->format('c'),
                        0,
                        strlen('2018-01-01T00:00:00')
                    )
                ]
            ]);

            return $response->success() ? $response->getData()[0]['Status'] === 'programmed' : false;
        }

        // put
        if (in_array($status, ['programmed', 'draft'])) {
            $response = $this->client->put(Resources::$CampaigndraftSchedule, [
                'ID' => $this->campaign,
                'Body' => [
                    'Date' => substr(
                        $this->datetime->format('c'),
                        0,
                        strlen('2018-01-01T00:00:00')
                    )
                ]
            ]);

            return $response->success() ? $response->getData()[0]['Status'] === 'programmed' : false;
        }

        return false;
    }

    public function cancelSchedule(): bool
    {
        if (! $this->campaign) {
            return false;
        }

        $response = $this->client->delete(Resources::$CampaigndraftSchedule, [
            'ID' => $this->campaign
        ]);

        return $response->getStatus() === 204;
    }

    public static function scheduled(): array
    {
        $response = mailjet()->client()->get(Resources::$Campaigndraft, [
            'Filters' => [
                'Status' => '1',
                //'Status' => '0', // '0' = ALL, else comma seperated list
                // -2 : deleted
                // -1 : archived draft
                // 0 : draft
                // 1 : programmed => schedule
                // 2 : sent
                // 3 : A/X testing
            ]
        ]);

        return $response->success() && count($response->getData()) ?
            array_map(static function ($value) {
                return [
                    'Name' => $value['Subject'],
                    'Value' => $value['ID'],
                    'Date' => $value['Date'],
                ];
            }, $response->getData()) : [];
    }
}