Send::printResult()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 13
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 23
ccs 0
cts 14
cp 0
crap 6
rs 9.8333
1
<?php
2
3
namespace Slides\Connector\Auth\Clients\Mandrill\Commands;
4
5
use Exception;
6
use Illuminate\Console\Command;
7
use Illuminate\Support\Fluent;
8
use Illuminate\Support\Str;
9
use Slides\Connector\Auth\Clients\Mandrill\Client;
10
use Slides\Connector\Auth\Clients\Mandrill\Mailer;
11
use Slides\Connector\Auth\Helpers\ConsoleHelper;
12
13
/**
14
 * Class Send
15
 *
16
 * @package Slides\Connector\Auth\Clients\Mandrill\Commands
17
 */
18
class Send extends Command
19
{
20
    /**
21
     * The name and signature of the console command.
22
     *
23
     * @var string
24
     */
25
    protected $signature = 'mandrill:send
26
                           {--r|recipients=   : The list of recipients or name of the file with recipients }
27
                           {--t|template=     : Name of the email template }
28
                           {--p|params=       : The list of parameters for an email }
29
                           {--c|context=      : The list of context variables }
30
                           {--f|from=         : The sender email address and name }
31
                           {--apiToken=       : The Mandrill API token }
32
                           {--s|subject=      : The message subject }
33
                           {--tags=           : The list of message tags }';
34
35
    /**
36
     * The console command description.
37
     *
38
     * @var string
39
     */
40
    protected $description = 'Send a new transactional message through Mandrill using a template.';
41
42
    /**
43
     * @var Client
44
     */
45
    protected $client;
46
47
    /**
48
     * @var array
49
     */
50
    protected $result = [
51
        'requests' => 0,
52
        'emails' => 0,
53
        'success' => 0,
54
        'failed' => [],
55
        'responses' => null
56
    ];
57
58
    /**
59
     * @var Mailer
60
     */
61
    protected $mailer;
62
63
    /**
64
     * Send constructor.
65
     *
66
     * @param Mailer $mailer
67
     */
68
    public function __construct(Mailer $mailer)
69
    {
70
        $this->mailer = $mailer;
71
72
        parent::__construct();
73
    }
74
75
    /**
76
     * Execute the console command.
77
     *
78
     * @return void|null
79
     *
80
     * @throws Exception
81
     */
82
    public function handle()
83
    {
84
        $recipients = $this->resolveRecipients();
85
86
        if ($secret = $this->option('apiToken')) {
87
            $this->mailer = $this->mailer->setToken($secret);
88
        }
89
90
        if (!$template = $this->option('template')) {
91
            throw new Exception('Please, pass the --template option');
92
        }
93
94
        $builder = $this->mailer->template($template)
95
            ->recipients($recipients)
96
            ->variables(ConsoleHelper::stringToArray($this->option('params')))
97
            ->context(ConsoleHelper::stringToArray($this->option('context')))
98
            ->tags(ConsoleHelper::stringToArray($this->option('tags')));
99
100
        if ($from = $this->option('from')) {
101
            $builder->from(...array_pad(explode(':', $from), 2, null));
0 ignored issues
show
Bug introduced by
array_pad(explode(':', $from), 2, null) is expanded, but the parameter $email of Slides\Connector\Auth\Cl...\Builders\Email::from() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
            $builder->from(/** @scrutinizer ignore-type */ ...array_pad(explode(':', $from), 2, null));
Loading history...
102
        }
103
104
        if ($subject = $this->option('subject')) {
105
            $builder->subject($subject);
106
        }
107
108
        if (!$this->confirm('Do you want to send ' . count($recipients) . ' emails?', true)) {
109
            return;
110
        }
111
112
        $start = time();
113
114
        $bar = $this->output->createProgressBar();
115
        $this->output->newLine('2');
116
        $bar->start(count($recipients));
117
118
        foreach ($builder->sendChunk(1000) as $response) {
119
            $this->parseResponse($response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type null and string; however, parameter $response of Slides\Connector\Auth\Cl...s\Send::parseResponse() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

119
            $this->parseResponse(/** @scrutinizer ignore-type */ $response);
Loading history...
120
121
            $bar->advance(count($response));
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type string; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
            $bar->advance(count(/** @scrutinizer ignore-type */ $response));
Loading history...
122
        }
123
124
        $bar->finish();
125
126
        $this->output->newLine(2);
127
128
        $this->result['spent'] = time() - $start;
129
130
        $this->printResult(new Fluent($this->result));
131
    }
132
133
    /**
134
     * Resolve email recipients.
135
     *
136
     * @return array|null
137
     *
138
     * @throws Exception
139
     */
140
    protected function resolveRecipients(): ?array
141
    {
142
        if (!$option = $this->option('recipients')) {
143
            throw new Exception('Please, pass the --recipients option');
144
        }
145
146
        return Str::contains($option, '@')
147
            ? ConsoleHelper::stringToArray($option)
148
            : explode(PHP_EOL, file_get_contents($option));
149
    }
150
151
    /**
152
     * Parse Mandrill response.
153
     *
154
     * @param array $response
155
     *
156
     * @return void
157
     */
158
    protected function parseResponse(array $response): void
159
    {
160
        $result = collect($response);
161
162
        $this->result['requests']++;
163
        $this->result['emails'] += $result->count();
164
        $this->result['success'] += $result->whereNotIn('status', ['rejected', 'invalid'])->count();
165
166
        $this->result['failed'] = $result->whereIn('status', ['rejected', 'invalid'])->pluck('email')->merge($this->result['failed'])->toArray();
167
        $this->result['responses'] .= json_encode($response) . PHP_EOL;
168
    }
169
170
    /**
171
     * Print the result of execution.
172
     *
173
     * @param Fluent $result
174
     *
175
     * @return void
176
     */
177
    protected function printResult(Fluent $result): void
178
    {
179
        $this->warn('######################################################');
180
181
        $this->comment('Number of requests: ' . $result->get('requests'));
182
        $this->comment('Number of emails: ' . $result->get('emails'));
183
        $this->comment('Success: ' . $result->get('success'));
184
        $this->comment('Total time spent: ' . $result->get('spent') . 's');
185
186
        if ($failed = $result->get('failed')) {
187
            $filename = 'mandrill_failed_emails_' . time() . '.log';
188
189
            file_put_contents(storage_path('logs/' . $filename), implode(PHP_EOL, $failed));
190
191
            $this->output->newLine();
192
            $this->error('Failed emails saved to ' . $filename);
193
        }
194
195
        $responsesFilename = 'mandrill_responses_' . time() . '.log';
196
197
        file_put_contents(storage_path('logs/' . $responsesFilename), $result->get('responses'));
198
199
        $this->info('Responses saved to ' . $responsesFilename);
200
    }
201
}