Passed
Push — master ( 80e19c...0a10f9 )
by Mathew
06:07 queued 03:07
created

LaravelInvites::validateEmailBeforeGeneration()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 14
rs 9.2222
c 0
b 0
f 0
cc 6
nc 4
nop 1
1
<?php
2
3
namespace mathewparet\LaravelInvites;
4
5
use mathewparet\LaravelInvites\Exceptions\InvalidInvitationCodeException;
6
use mathewparet\LaravelInvites\Exceptions\InvalidEmailIdException;
7
use mathewparet\LaravelInvites\Exceptions\InvitationNotYetActiveException;
8
use mathewparet\LaravelInvites\Exceptions\InvitationExpiredException;
9
use mathewparet\LaravelInvites\Exceptions\InvitationNotValidWithEmailException;
10
use mathewparet\LaravelInvites\Exceptions\MaximumUseOfCodeException;
11
use mathewparet\LaravelInvites\Exceptions\LaravelInvitesException;
12
use mathewparet\LaravelInvites\Exceptions\AnEmailCanHaveOnlyOneInvitation;
13
14
use mathewparet\LaravelInvites\Mail\InvitationMail;
15
16
use Illuminate\Support\Facades\Mail;
17
18
use Carbon\Carbon;
19
use Validator;
20
21
use mathewparet\LaravelInvites\Models\Invite;
22
23
class LaravelInvites
24
{
25
    private $number_of_invites = 1;
26
    private $data = [];
27
28
    /**
29
     * Initialize the data attributes and reset values
30
     * 
31
     * @return void
32
     */
33
    private function initializeData()
34
    {
35
        $this->data = ['allowed_count' => 1];
36
    }
37
38
    public function __construct()
39
    {
40
        $this->initializeData();
41
    }
42
43
    /**
44
     * Get the invites from DB
45
     * 
46
     * @return mixed
47
     */
48
    public function get()
49
    {
50
        if (!blank(optional($this->data)['email'])) {
51
                    $result = Invite::valid()->whereEmail($this->data['email'])->first();
52
        } else {
53
                    $result = Invite::valid()->get();
54
        }
55
56
        $this->initializeData();
57
58
        return $result;
59
    }
60
61
    /**
62
     * Set the email property for generating or getting invitation
63
     * 
64
     * @param string $email
65
     * 
66
     * @return \mathewparet\LaravelInvites\Facades\LaravelInvites
67
     */
68
    public function for ($email = null)
69
    {
70
        if (!$email)
71
        {
72
            unset($this->data['email']);
73
            return $this;
74
        }
75
76
        $validator = Validator::make(compact('email'), [
77
            'email'=>'required|email'
78
        ]);
79
        if ($validator->fails()) {
80
                    throw new InvalidEmailIdException;
81
        }
82
83
        $this->data['email'] = $email;
84
85
        return $this;
86
    }
87
88
    /**
89
     * Create a single invite model
90
     * 
91
     * @return \mathewparet\LaravelInvites\Models\Invite
92
     */
93
    private function prepareSingle()
94
    {
95
        $invite = Invite::create($this->data);
96
97
        if ($invite->email && config('laravelinvites.mail.enabled', true)) {
0 ignored issues
show
Bug introduced by
The property email does not seem to exist on mathewparet\LaravelInvites\Models\Invite. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
98
                    Mail::to($invite->email)->send(new InvitationMail($invite));
99
        }
100
101
        return $invite;
102
    }
103
104
    /**
105
     * Get the validity start date for the invitation
106
     * 
107
     * @param \Carbon\Carbon $date
108
     * @return \mathewparet\LaravelInvites\Facades\LaravelInvites
109
     */
110
    public function validFrom(Carbon $date)
111
    {
112
        $this->data['valid_from'] = $date;
113
114
        return $this;
115
    }
116
117
    /**
118
     * Generate the requested invitations
119
     * 
120
     * @return mixed
121
     */
122
    private function prepare()
123
    {
124
        if ($this->number_of_invites == 1) {
125
                    return $this->prepareSingle();
126
        }
127
128
        $invites = [];
129
130
        for ($i = 0; $i < $this->number_of_invites; $i++)
131
        {
132
            $invites[] = $this->prepareSingle();
133
        }
134
135
        return $invites;
136
    }
137
138
    /**
139
     * Validate email ID before generating invitation code
140
     * 
141
     * @param integer $number_of_invites
142
     * 
143
     * @throws \mathewparet\LaravelInvites\Exceptions\AnEmailCanHaveOnlyOneInvitation
144
     */
145
    private function validateEmailBeforeGeneration($number_of_invites = 1)
146
    {
147
        if (optional($this->data)['email'] && !blank($this->data['email']))
148
        {
149
            if ($number_of_invites > 1 || $this->data['allowed_count'] > 1) {
150
                            throw new AnEmailCanHaveOnlyOneInvitation;
151
            }
152
153
            $validator = Validator::make($this->data, [
154
                'email'=>'unique:'.config('laravelinvites.table').',email'
155
            ]);
156
157
            if ($validator->fails()) {
158
                            throw new AnEmailCanHaveOnlyOneInvitation;
159
            }
160
        }
161
    }
162
163
    /**
164
     * Generate invitations
165
     * 
166
     * @param integer $number_of_invites | default = 1
167
     * 
168
     * @return mixed array of invitations generated
169
     */
170
    public function generate($number_of_invites = 1)
171
    {
172
        $this->validateEmailBeforeGeneration($number_of_invites);
173
174
        $this->number_of_invites = $number_of_invites;
175
176
        $invitations = $this->prepare();
177
        
178
        $this->initializeData();
179
180
        return $invitations;
181
    }
182
183
    /**
184
     * Set the number of uses allowed for this invite
185
     * 
186
     * @param integer $num_allowed
187
     * 
188
     * @return \mathewparet\LaravelInvites\Facades\LaravelInvites
189
     */
190
    public function allow($num_allowed = 1)
191
    {
192
        $this->data['allowed_count'] = $num_allowed;
193
194
        return $this;
195
    }
196
197
    /**
198
     * Generate a single invitiation to be used only by a specific email
199
     * 
200
     * @param string $email
201
     * 
202
     * @return mixed the invitation record
203
     */
204
    public function generateFor($email)
205
    {
206
        $this->for($email);
207
208
        return $this->generate(1);
209
    }
210
211
    /**
212
     * Set expiry to never expire
213
     * 
214
     * @return \mathewparet\LaravelInvites\Facades\LaravelInvites
215
     */
216
    public function withoutExpiry()
217
    {
218
        $this->data['valid_upto'] = null;
219
220
        return $this;
221
    }
222
223
    /**
224
     * Set an expiry date
225
     * 
226
     * @param \Carbon\Carbon $data
227
     */
228
    public function setExpiry(Carbon $date)
229
    {
230
        $this->data['valid_upto'] = $date;
231
232
        return $this;
233
    }
234
235
    /**
236
     * Find an invitation by code
237
     * 
238
     * @param string $code
239
     *
240
     * @return \mathewparet\LaravelInvites\Models\Invite $invite
241
     */
242
    public function find($code)
243
    {
244
        return Invite::whereCode($code)->firstOrFail();
245
    }
246
247
    /**
248
     * Identify the email attribute name from validator parameter
249
     * 
250
     * @param Array $parameters
251
     * 
252
     * @return string
253
     */
254
    private function getEmailParameter($parameters)
255
    {
256
        return $parameters[0] ?: 'email';
257
    }
258
    
259
    /**
260
     * Validate the form submission for a valid invitation code.
261
     * This is extended through validator.
262
     * 
263
     * @param String $attribute
264
     * @param String $value
265
     * @param Array $parameters
266
     * @param Validator $validator
267
     * 
268
     * @return boolean
269
     * 
270
     * @throws \mathewparet\LaravelInvites\Exceptions\LaravelInvitesException
271
     */
272
    public function validate(/** @scrutinizer ignore-unused */ $attribute, /** @scrutinizer ignore-unused */ $value, $parameters, $validator)
273
    {
274
        $emailFieldName = $this->getEmailParameter($parameters);
275
276
        try {        
277
            $email = $validator->data[$emailFieldName];
1 ignored issue
show
Bug introduced by
The property data does not seem to exist on Illuminate\Support\Facades\Validator.
Loading history...
278
279
            $this->check($value, $email);
280
            return true;
281
        } catch (InvalidInvitationCodeException $e)
282
        {
283
            $validator->errors()->add($emailFieldName, ':attribute is invalid');
1 ignored issue
show
Bug introduced by
The method errors() does not exist on Illuminate\Support\Facades\Validator. ( Ignorable by Annotation )

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

283
            $validator->/** @scrutinizer ignore-call */ 
284
                        errors()->add($emailFieldName, ':attribute is invalid');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
284
            return false;
285
        } catch (InvitationNotYetActiveException $e)
286
        {
287
            $validator->errors()->add($emailFieldName, ':attribute is not valid yet');
288
            return false;
289
        } catch (InvitationExpiredException $e)
290
        {
291
            $validator->errors()->add($emailFieldName, ':attribute expired');
292
            return false;
293
        } catch (InvitationNotValidWithEmailException $e)
294
        {
295
            $validator->errors()->add($emailFieldName, ':attribute is not valid with the provided '.$emailFieldName);
296
            return false;
297
        } catch (MaximumUseOfCodeException $e)
298
        {
299
            $validator->errors()->add($emailFieldName, ':attribute has been used for the maximum possible times');
300
            return false;
301
        }
302
    }
303
304
    /**
305
     * Check whether an invitation is valid with the provided email
306
     * 
307
     * @param string $code
308
     * @param string $email to be checked against
309
     * 
310
     * @return boolean
311
     */
312
313
    public function isValid($code, $email = null)
314
    {
315
        try
316
        {
317
            $this->check($code, $email);
318
319
            return true;
320
        } catch (LaravelInvitesException $e)
321
        {
322
            return false;
323
        }
324
    }
325
326
    /**
327
     * Check the validity of the invitiation code
328
     * 
329
     * @param string $code
330
     * @param string $email
331
     * 
332
     * @return boolean
333
     */
334
    public function check($code, $email = null)
335
    {
336
        $invite = Invite::whereCode($code)->first();
337
338
        if (!$invite) {
339
                    throw new InvalidInvitationCodeException;
340
        }
341
        
342
        if ($invite->valid_from > now()) {
343
                    throw new InvitationNotYetActiveException($invite->valid_from);
344
        }
345
346
        if ($invite->valid_upto && $invite->valid_upto <= now()) {
347
                    throw new InvitationExpiredException($invite->valid_upto);
348
        }
349
350
        if ($invite->used_count > ($invite->allowed_count - 1)) {
0 ignored issues
show
Bug introduced by
The property used_count does not seem to exist on mathewparet\LaravelInvites\Models\Invite. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
351
                    throw new MaximumUseOfCodeException($invite->allowed_count);
352
        }
353
354
        if ($invite->email !== $email && !blank($invite->email)) {
0 ignored issues
show
Bug introduced by
The property email does not seem to exist on mathewparet\LaravelInvites\Models\Invite. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
355
                    throw new InvitationNotValidWithEmailException($email, $invite->email);
356
        }
357
358
        return true;
359
    }
360
361
    /**
362
     * Redeem the invitation code. Make sure the form field is validated before this calls to avoid exceptions
363
     * 
364
     * @param string $code
365
     * @param string $email (optional)
366
     * 
367
     * @return boolean
368
     */
369
370
    public function redeem($code, $email = null)
371
    {
372
        $this->check($code, $email);
373
     
374
        $this->find($code)->redeem();
375
376
        return true;
377
    }
378
379
    /**
380
     * Set a validity start date for the invitation
381
     * 
382
     * @param \Carbon\Carbon $date
383
     * 
384
     * @return \mathewparet\LaravelInvites\Facades\LaravelInvites
385
     */
386
    public function notBefore(Carbon $date)
387
    {
388
        $this->data['valid_from'] = $date;
389
        return $this;
390
    }
391
392
}