Completed
Push — issue-118 ( 68e7b7...8e2bf8 )
by
unknown
02:25
created

NotifynderBuilder::loop()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 3 Features 2
Metric Value
c 9
b 3
f 2
dl 0
loc 22
rs 8.9197
cc 4
eloc 14
nc 4
nop 2
1
<?php namespace Fenos\Notifynder\Builder;
2
3
use ArrayAccess;
4
use Carbon\Carbon;
5
use Fenos\Notifynder\Contracts\NotifynderCategory;
6
use Fenos\Notifynder\Exceptions\EntityNotIterableException;
7
use Fenos\Notifynder\Exceptions\IterableIsEmptyException;
8
use Fenos\Notifynder\Exceptions\NotificationBuilderException;
9
use Illuminate\Contracts\Config\Repository;
10
use Illuminate\Database\Eloquent\Model;
11
use Traversable;
12
use Closure;
13
14
/**
15
 * Class NotifynderBuilder
16
 *
17
 * The builder is a main factor of Notifynder, it make sure
18
 * that the notification is decorated and validated before
19
 * are passed to the Sender Classes. It also helps you to
20
 * create multi notifications with the same simple and easy sintax.
21
 *
22
 * @package Fenos\Notifynder\Builder
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
    function __construct(NotifynderCategory $notifynderCategory)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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 datas 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
            if(count($dataToIterate) > 0) {
186
                $notifications = [];
187
188
                $newBuilder = new self($this->notifynderCategory);
189
190
                foreach ($dataToIterate as $key => $data) {
191
                    $builder($newBuilder, $data, $key);
192
                    $notifications[] = $newBuilder->toArray();
193
                }
194
195
                $this->notifications = $notifications;
196
                return $this;
197
            } else {
198
                throw new IterableIsEmptyException('The Iterable passed must contain at least one element');
199
            }
200
        } else {
201
            throw new EntityNotIterableException('The data passed must be itarable');
202
        }
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
220
            $this->setDate();
221
222
            if ($this->hasRequiredFields($this->notifications)) {
223
                return $this->notifications;
224
            }
225
        }
226
227
        // If has multiple Notifications
228
        // we will validate one by one
229
        if ($hasMultipleNotifications) {
230
231
            $allow = [];
232
233
            foreach($this->notifications as $index => $notification) {
234
                $allow[$index] = $this->hasRequiredFields($notification);
235
            }
236
237
            if (! in_array(false,$allow)) {
238
                return $this->notifications;
239
            }
240
        }
241
242
        $error = "The fields: ".implode(',', $this->getRequiredFields())." are required";
243
        throw new NotificationBuilderException($error);
244
    }
245
246
    /**
247
     * Refresh the state of the notifications
248
     */
249
    public function refresh()
250
    {
251
        $this->notifications = [];
252
253
        return $this;
254
    }
255
256
    /**
257
     * @param $var
258
     * @return bool
259
     */
260
    protected function isIterable($var)
261
    {
262
        return (is_array($var) || $var instanceof Traversable);
263
    }
264
265
    /**
266
     * It set the entity who will do
267
     * the action of receive or
268
     * send
269
     *
270
     * @param $from
271
     * @param $property
272
     * @return array
273
     */
274
    protected function setEntityAction($from, $property)
275
    {
276
        // Check if has the entity as parameter
277
        // it should be the firstOne
278
        if ($this->hasEntity($from)) {
279
            $this->isString($from[0]);
280
            $this->isNumeric($from[1]);
281
282
            $this->setBuilderData("{$property}_type", $from[0]);
283
            $this->setBuilderData("{$property}_id", $from[1]);
284
        } elseif($from[0] instanceof Model) {
285
            $this->setBuilderData("{$property}_type", $from[0]->getMorphClass());
286
            $this->setBuilderData("{$property}_id", $from[0]->getKey());
287
        } else {
288
            $this->isNumeric($from[0]);
289
            $this->setBuilderData("{$property}_id", $from[0]);
290
        }
291
    }
292
293
    /**
294
     * If the values passed are 2 or more,
295
     * it means that you spefied the entity
296
     * over then the id
297
     *
298
     * @param  array $info
299
     * @return bool
300
     */
301
    protected function hasEntity(array $info)
302
    {
303
        return count($info) >= 2;
304
    }
305
306
    /**
307
     * Set date on the array
308
     */
309
    protected function setDate()
310
    {
311
        $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...
312
313
        $this->setBuilderData('updated_at', $data);
314
        $this->setBuilderData('created_at', $data);
315
    }
316
317
    /**
318
     * @return string
319
     */
320
    protected function getDate()
321
    {
322
        return $this->date;
323
    }
324
325
    /**
326
     * Set builder Data
327
     *
328
     * @param $field
329
     * @param $data
330
     */
331
    public function setBuilderData($field, $data)
332
    {
333
        return $this->notifications[$field] = $data;
334
    }
335
336
337
    /**
338
     * @param mixed $offset
339
     * @return bool
340
     */
341
    public function offsetExists($offset)
342
    {
343
        return array_key_exists($offset,$this->notifications);
344
    }
345
346
347
    /**
348
     * @param mixed $offset
349
     * @return mixed
350
     */
351
    public function offsetGet($offset)
352
    {
353
        return $this->notifications[$offset];
354
    }
355
356
357
    /**
358
     * @param mixed $offset
359
     * @param mixed $value
360
     */
361
    public function offsetSet($offset, $value)
362
    {
363
        if (method_exists($this, $offset)) {
364
365
            return $this->{$offset}($value);
366
        }
367
368
        if ($this->isRequiredField($offset)) {
369
            $this->notifications[$offset] = $value;
370
        }
371
    }
372
373
    /**
374
     * @param Repository $config
375
     */
376
    public function setConfig(Repository $config)
377
    {
378
        $this->config = $config;
379
    }
380
381
    /**
382
     * @param mixed $offset
383
     * @return null
384
     */
385
    public function offsetUnset($offset)
386
    {
387
        unset($this->notifications[$offset]);
388
    }
389
}
390