Completed
Push — master ( 9abbc7...a687e5 )
by Fabrizio
03:03
created

NotifynderBuilder::toArray()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 31
rs 8.439
cc 6
eloc 14
nc 7
nop 0
1
<?php
2
3
namespace Fenos\Notifynder\Builder;
4
5
use ArrayAccess;
6
use Carbon\Carbon;
7
use Fenos\Notifynder\Contracts\NotifynderCategory;
8
use Fenos\Notifynder\Exceptions\EntityNotIterableException;
9
use Fenos\Notifynder\Exceptions\IterableIsEmptyException;
10
use Fenos\Notifynder\Exceptions\NotificationBuilderException;
11
use Illuminate\Contracts\Config\Repository;
12
use Illuminate\Database\Eloquent\Model;
13
use Traversable;
14
use Closure;
15
16
/**
17
 * Class NotifynderBuilder.
18
 *
19
 * The builder is a main factor of Notifynder, it make sure
20
 * that the notification is decorated and validated before
21
 * are passed to the Sender Classes. It also helps you to
22
 * create multi notifications with the same simple and easy syntax.
23
 */
24
class NotifynderBuilder implements ArrayAccess
25
{
26
    use BuilderRules;
27
28
    /**
29
     * @var string notification to store
30
     */
31
    public $date;
32
33
    /**
34
     * Builder data.
35
     *
36
     * @var array
37
     */
38
    protected $notifications = [];
39
40
    /**
41
     * @var Repository
42
     */
43
    protected $config;
44
45
    /**
46
     * @var NotifynderCategory
47
     */
48
    private $notifynderCategory;
49
50
    /**
51
     * @param NotifynderCategory $notifynderCategory
52
     */
53
    public function __construct(NotifynderCategory $notifynderCategory)
54
    {
55
        $this->notifynderCategory = $notifynderCategory;
56
    }
57
58
    /**
59
     * Set who will send the notification.
60
     *
61
     * @return $this
62
     */
63
    public function from()
64
    {
65
        $from = func_get_args();
66
67
        $this->setEntityAction($from, 'from');
68
69
        return $this;
70
    }
71
72
    /**
73
     * Set who will receive the notification.
74
     *
75
     * @return $this
76
     */
77
    public function to()
78
    {
79
        $from = func_get_args();
80
81
        $this->setEntityAction($from, 'to');
82
83
        return $this;
84
    }
85
86
    /**
87
     * Set the url of the notification.
88
     *
89
     * @param $url
90
     * @return $this
91
     */
92
    public function url($url)
93
    {
94
        $this->isString($url);
95
96
        $this->setBuilderData('url', $url);
97
98
        return $this;
99
    }
100
101
    /**
102
     * Set expire time.
103
     *
104
     * @param $datetime
105
     * @return $this
106
     */
107
    public function expire($datetime)
108
    {
109
        $this->isCarbon($datetime);
110
        $this->setBuilderData('expire_time', $datetime);
111
112
        return $this;
113
    }
114
115
    /**
116
     * Set Category and covert it, to the id
117
     * if name of it given.
118
     *
119
     * @param $category
120
     * @return $this
121
     */
122
    public function category($category)
123
    {
124
        if (! is_numeric($category)) {
125
            $category = $this->notifynderCategory
126
                            ->findByName($category)->id;
127
        }
128
129
        $this->setBuilderData('category_id', $category);
130
131
        return $this;
132
    }
133
134
    /**
135
     * Set extra value.
136
     *
137
     * @param $extra
138
     * @return $this
139
     */
140
    public function extra(array $extra = [])
141
    {
142
        $this->isReadyArrToFormatInJson($extra);
143
144
        $jsonExtraValues = json_encode($extra);
145
146
        $this->setBuilderData('extra', $jsonExtraValues);
147
148
        return $this;
149
    }
150
151
    /**
152
     * Build the array with the builder inside
153
     * a Closure, it has more flexibility for
154
     * the generation of your array.
155
     *
156
     *
157
     * @param callable|Closure $closure
158
     * @return array|false
159
     * @throws NotificationBuilderException
160
     */
161
    public function raw(Closure $closure)
162
    {
163
        $builder = $closure($this);
164
165
        if (! is_null($builder)) {
166
            return $this->toArray();
167
        }
168
169
        return false;
170
    }
171
172
    /**
173
     * Loop the data for create
174
     * multi notifications array.
175
     *
176
     * @param          $dataToIterate
177
     * @param  Closure $builder
178
     * @return $this
179
     * @throws \Fenos\Notifynder\Exceptions\IterableIsEmptyException
180
     * @throws \Fenos\Notifynder\Exceptions\EntityNotIterableException
181
     */
182
    public function loop($dataToIterate, Closure $builder)
183
    {
184
        if (! $this->isIterable($dataToIterate)) {
185
            throw new EntityNotIterableException('The data passed must be iterable');
186
        }
187
        if (count($dataToIterate) <= 0) {
188
            throw new IterableIsEmptyException('The Iterable passed must contain at least one element');
189
        }
190
191
        $notifications = [];
192
193
        $newBuilder = new self($this->notifynderCategory);
194
195
        foreach ($dataToIterate as $key => $data) {
196
            $builder($newBuilder, $data, $key);
197
            $notifications[] = $newBuilder->toArray();
198
        }
199
200
        $this->notifications = $notifications;
201
202
        return $this;
203
    }
204
205
    /**
206
     * Compose the builder to
207
     * the array.
208
     *
209
     * @throws NotificationBuilderException
210
     * @return mixed
211
     */
212
    public function toArray()
213
    {
214
        $hasMultipleNotifications = $this->isMultidimensionalArray($this->notifications);
215
216
        // If the builder is handling a single notification
217
        // we will validate only it
218
        if (! $hasMultipleNotifications) {
219
            $this->setDate();
220
221
            if ($this->hasRequiredFields($this->notifications)) {
222
                return $this->notifications;
223
            }
224
        }
225
226
        // If has multiple Notifications
227
        // we will validate one by one
228
        if ($hasMultipleNotifications) {
229
            $allow = [];
230
231
            foreach ($this->notifications as $index => $notification) {
232
                $allow[$index] = $this->hasRequiredFields($notification);
233
            }
234
235
            if (! in_array(false, $allow)) {
236
                return $this->notifications;
237
            }
238
        }
239
240
        $error = 'The fields: '.implode(',', $this->getRequiredFields()).' are required';
241
        throw new NotificationBuilderException($error);
242
    }
243
244
    /**
245
     * Refresh the state of the notifications.
246
     */
247
    public function refresh()
248
    {
249
        $this->notifications = [];
250
251
        return $this;
252
    }
253
254
    /**
255
     * @param $var
256
     * @return bool
257
     */
258
    protected function isIterable($var)
259
    {
260
        return is_array($var) || $var instanceof Traversable;
261
    }
262
263
    /**
264
     * It set the entity who will do
265
     * the action of receive or
266
     * send.
267
     *
268
     * @param $from
269
     * @param $property
270
     * @return array
271
     */
272
    protected function setEntityAction($from, $property)
273
    {
274
        // Check if has the entity as parameter
275
        // it should be the firstOne
276
        if ($this->hasEntity($from)) {
277
            $this->isString($from[0]);
278
            $this->isNumeric($from[1]);
279
280
            $this->setBuilderData("{$property}_type", $from[0]);
281
            $this->setBuilderData("{$property}_id", $from[1]);
282
        } elseif ($from[0] instanceof Model) {
283
            $this->setBuilderData("{$property}_type", $from[0]->getMorphClass());
284
            $this->setBuilderData("{$property}_id", $from[0]->getKey());
285
        } else {
286
            $this->isNumeric($from[0]);
287
            $this->setBuilderData("{$property}_id", $from[0]);
288
        }
289
    }
290
291
    /**
292
     * If the values passed are 2 or more,
293
     * it means that you specified the entity
294
     * over then the id.
295
     *
296
     * @param  array $info
297
     * @return bool
298
     */
299
    protected function hasEntity(array $info)
300
    {
301
        return count($info) >= 2;
302
    }
303
304
    /**
305
     * Set date on the array.
306
     */
307
    protected function setDate()
308
    {
309
        $this->date = $data = Carbon::now();
0 ignored issues
show
Documentation Bug introduced by
It seems like $data = \Carbon\Carbon::now() of type object<Carbon\Carbon> is incompatible with the declared type string of property $date.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
310
311
        $this->setBuilderData('updated_at', $data);
312
        $this->setBuilderData('created_at', $data);
313
    }
314
315
    /**
316
     * @return string
317
     */
318
    protected function getDate()
319
    {
320
        return $this->date;
321
    }
322
323
    /**
324
     * Set builder Data.
325
     *
326
     * @param $field
327
     * @param $data
328
     */
329
    public function setBuilderData($field, $data)
330
    {
331
        return $this->notifications[$field] = $data;
332
    }
333
334
    /**
335
     * @param mixed $offset
336
     * @return bool
337
     */
338
    public function offsetExists($offset)
339
    {
340
        return array_key_exists($offset, $this->notifications);
341
    }
342
343
    /**
344
     * @param mixed $offset
345
     * @return mixed
346
     */
347
    public function offsetGet($offset)
348
    {
349
        return $this->notifications[$offset];
350
    }
351
352
    /**
353
     * @param mixed $offset
354
     * @param mixed $value
355
     */
356
    public function offsetSet($offset, $value)
357
    {
358
        if (method_exists($this, $offset)) {
359
            return $this->{$offset}($value);
360
        }
361
362
        if ($this->isRequiredField($offset)) {
363
            $this->notifications[$offset] = $value;
364
        }
365
    }
366
367
    /**
368
     * @param Repository $config
369
     */
370
    public function setConfig(Repository $config)
371
    {
372
        $this->config = $config;
373
    }
374
375
    /**
376
     * @param mixed $offset
377
     * @return null
378
     */
379
    public function offsetUnset($offset)
380
    {
381
        unset($this->notifications[$offset]);
382
    }
383
}
384