Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
78 / 78
100.00% covered (success)
100.00%
28 / 28
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractAdapter
100.00% covered (success)
100.00%
78 / 78
100.00% covered (success)
100.00%
28 / 28
49
100.00% covered (success)
100.00%
1 / 1
 setModel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setModelId
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getModel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModelId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAction
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOriginal
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModified
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setUsername
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setUserId
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setDomain
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setRoute
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setMethod
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setMetadata
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addMetadata
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUsername
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUserId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDomain
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRoute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMethod
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasMetadata
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getMetadata
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 setStateData
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getStateData
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 hasStateData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 setDiff
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 resolveDiff
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
7
 hasDiff
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 prepareData
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
5
 send
n/a
0 / 0
n/a
0 / 0
0
 getStates
n/a
0 / 0
n/a
0 / 0
0
 getStateById
n/a
0 / 0
n/a
0 / 0
0
 getStateByModel
n/a
0 / 0
n/a
0 / 0
0
 getStateByTimestamp
n/a
0 / 0
n/a
0 / 0
0
 getStateByDate
n/a
0 / 0
n/a
0 / 0
0
 getSnapshot
n/a
0 / 0
n/a
0 / 0
0
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Audit\Adapter;
15
16/**
17 * Auditor abstract adapter
18 *
19 * @category   Pop
20 * @package    Pop\Audit
21 * @author     Nick Sagona, III <dev@nolainteractive.com>
22 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
23 * @license    http://www.popphp.org/license     New BSD License
24 * @version    2.0.0
25 */
26abstract class AbstractAdapter implements AdapterInterface
27{
28
29    /**
30     * Constants for action states
31     * @var int
32     */
33    const CREATED = 'created';
34    const UPDATED = 'updated';
35    const DELETED = 'deleted';
36
37    /**
38     * Model name
39     * @var ?string
40     */
41    protected ?string $model = null;
42
43    /**
44     * Model ID
45     * @var int|string|null
46     */
47    protected int|string|null $modelId = null;
48
49    /**
50     * Action (created, updated, deleted)
51     * @var ?string
52     */
53    protected ?string $action = null;
54
55    /**
56     * Original model state differences
57     * @var array
58     */
59    protected array $original = [];
60
61    /**
62     * Modified model state differences
63     * @var array
64     */
65    protected array $modified = [];
66
67    /**
68     * Final state data
69     * @var array
70     */
71    protected array $stateData = [];
72
73    /**
74     * Username
75     * @var ?string
76     */
77    protected ?string $username = null;
78
79    /**
80     * User ID
81     * @var int|string|null
82     */
83    protected int|string|null $userId = null;
84
85    /**
86     * Domain
87     * @var ?string
88     */
89    protected ?string $domain = null;
90
91    /**
92     * Route
93     * @var ?string
94     */
95    protected ?string $route = null;
96
97    /**
98     * Method
99     * @var ?string
100     */
101    protected ?string $method = null;
102
103    /**
104     * Metadata
105     * @var array
106     */
107    protected array$metadata = [];
108
109    /**
110     * Set the model name
111     *
112     * @param  string $model
113     * @return AbstractAdapter
114     */
115    public function setModel(string $model): AbstractAdapter
116    {
117        $this->model = $model;
118        return $this;
119    }
120
121    /**
122     * Set the model ID
123     *
124     * @param  int|string $modelId
125     * @return AbstractAdapter
126     */
127    public function setModelId(int|string $modelId): AbstractAdapter
128    {
129        $this->modelId = $modelId;
130        return $this;
131    }
132
133    /**
134     * Get the model name
135     *
136     * @return string|null
137     */
138    public function getModel(): string|null
139    {
140        return $this->model;
141    }
142
143    /**
144     * Get the model ID
145     *
146     * @return int|string|null
147     */
148    public function getModelId(): int|string|null
149    {
150        return $this->modelId;
151    }
152
153    /**
154     * Get the action
155     *
156     * @return string|null
157     */
158    public function getAction(): string|null
159    {
160        return $this->action;
161    }
162
163    /**
164     * Get the original model state differences
165     *
166     * @return array
167     */
168    public function getOriginal(): array
169    {
170        return $this->original;
171    }
172
173    /**
174     * Get the modified model state differences
175     *
176     * @return array
177     */
178    public function getModified(): array
179    {
180        return $this->modified;
181    }
182
183    /**
184     * Set the username
185     *
186     * @param  string $username
187     * @return AbstractAdapter
188     */
189    public function setUsername(string $username): AbstractAdapter
190    {
191        $this->username = $username;
192        return $this;
193    }
194
195    /**
196     * Set the user ID
197     *
198     * @param  int|string $userId
199     * @return AbstractAdapter
200     */
201    public function setUserId(int|string $userId): AbstractAdapter
202    {
203        $this->userId = $userId;
204        return $this;
205    }
206
207    /**
208     * Set the domain
209     *
210     * @param  string $domain
211     * @return AbstractAdapter
212     */
213    public function setDomain(string $domain): AbstractAdapter
214    {
215        $this->domain = $domain;
216        return $this;
217    }
218
219    /**
220     * Set the route
221     *
222     * @param  string $route
223     * @return AbstractAdapter
224     */
225    public function setRoute($route): AbstractAdapter
226    {
227        $this->route = $route;
228        return $this;
229    }
230
231    /**
232     * Set the method
233     *
234     * @param  string $method
235     * @return AbstractAdapter
236     */
237    public function setMethod(string $method): AbstractAdapter
238    {
239        $this->method = $method;
240        return $this;
241    }
242
243    /**
244     * Set the metadata
245     *
246     * @param  array $metadata
247     * @return AbstractAdapter
248     */
249    public function setMetadata(array $metadata): AbstractAdapter
250    {
251        $this->metadata = $metadata;
252        return $this;
253    }
254
255    /**
256     * Add to the metadata
257     *
258     * @param  string $name
259     * @param  mixed $value
260     * @return AbstractAdapter
261     */
262    public function addMetadata(string $name, mixed $value): AbstractAdapter
263    {
264        $this->metadata[$name] = $value;
265        return $this;
266    }
267
268    /**
269     * Get the username
270     *
271     * @return string|null
272     */
273    public function getUsername(): string|null
274    {
275        return $this->username;
276    }
277
278    /**
279     * Get the user ID
280     *
281     * @return int|string|null
282     */
283    public function getUserId(): int|string|null
284    {
285        return $this->userId;
286    }
287
288    /**
289     * Get the domain
290     *
291     * @return string|null
292     */
293    public function getDomain(): string|null
294    {
295        return $this->domain;
296    }
297
298    /**
299     * Get the route
300     *
301     * @return string|null
302     */
303    public function getRoute(): string|null
304    {
305        return $this->route;
306    }
307
308    /**
309     * Get the method
310     *
311     * @return string|null
312     */
313    public function getMethod(): string|null
314    {
315        return $this->method;
316    }
317
318    /**
319     * Determine if there is metadata
320     *
321     * @param  ?string $name
322     * @return bool
323     */
324    public function hasMetadata(?string $name = null): bool
325    {
326        if ($name !== null) {
327            return isset($this->metadata[$name]);
328        } else {
329            return !empty($this->metadata);
330        }
331    }
332
333    /**
334     * Get the metadata
335     *
336     * @param  ?string $name
337     * @return mixed
338     */
339    public function getMetadata(?string $name = null): mixed
340    {
341        if ($name !== null) {
342            return (isset($this->metadata[$name])) ? $this->metadata[$name] : null;
343        } else {
344            return $this->metadata;
345        }
346    }
347
348    /**
349     * Set the final state data
350     *
351     * @param  array $state
352     * @return AbstractAdapter
353     */
354    public function setStateData(array $state): AbstractAdapter
355    {
356        $this->stateData = $state;
357        return $this;
358    }
359
360    /**
361     * Get the final state
362     *
363     * @param  ?string $name
364     * @return mixed
365     */
366    public function getStateData(?string $name = null): mixed
367    {
368        if ($name !== null) {
369            return (isset($this->stateData[$name])) ? $this->stateData[$name] : null;
370        } else {
371            return $this->stateData;
372        }
373    }
374
375    /**
376     * Determine if there is final state data
377     *
378     * @param  ?string $name
379     * @return bool
380     */
381    public function hasStateData(?string $name = null): bool
382    {
383        return ($name !== null) ? array_key_exists($name, $this->stateData) : !empty($this->stateData);
384    }
385
386    /**
387     * Set the differences in values between the model states (that have already been processed)
388     *
389     * @param  array $old
390     * @param  array $new
391     * @return AbstractAdapter
392     */
393    public function setDiff(array $old = [], array $new = []): AbstractAdapter
394    {
395        $this->original = $old;
396        $this->modified = $new;
397
398        if (empty($old) && !empty($new)) {
399            $this->action = AbstractAdapter::CREATED;
400        } else if (empty($new) && !empty($old)) {
401            $this->action = AbstractAdapter::DELETED;
402        } else {
403            $this->action = AbstractAdapter::UPDATED;
404        }
405
406        return $this;
407    }
408
409    /**
410     * Resolve the differences in values between the model states
411     *
412     * @param  array $old
413     * @param  array $new
414     * @param  bool  $state
415     * @return AbstractAdapter
416     */
417    public function resolveDiff(array $old = [], array $new = [], bool $state = true): AbstractAdapter
418    {
419        if ($state) {
420            $this->setStateData($new);
421        }
422        if (empty($old) && !empty($new)) {
423            $this->modified = $new;
424            $this->action   = AbstractAdapter::CREATED;
425        } else if (empty($new) && !empty($old)) {
426            $this->original = $old;
427            $this->action   = AbstractAdapter::DELETED;
428        } else {
429            $keys = array_keys(array_diff($old, $new));
430            foreach ($keys as $key) {
431                $this->original[$key] = $old[$key];
432                $this->modified[$key] = $new[$key];
433            }
434            $this->action = AbstractAdapter::UPDATED;
435        }
436
437        return $this;
438    }
439
440    /**
441     * Check if the model states are different
442     *
443     * @return bool
444     */
445    public function hasDiff(): bool
446    {
447        return (($this->action !== null) && ($this->original !== $this->modified));
448    }
449
450    /**
451     * Prepare data
452     *
453     * @param  bool $jsonEncode
454     * @return array
455     */
456    public function prepareData(bool $jsonEncode = true): array
457    {
458        return [
459            'user_id'   => $this->userId,
460            'username'  => $this->username,
461            'domain'    => $this->domain,
462            'route'     => $this->route,
463            'method'    => $this->method,
464            'model'     => $this->model,
465            'model_id'  => $this->modelId,
466            'action'    => $this->action,
467            'old'       => ($jsonEncode) ? json_encode($this->original) : $this->original,
468            'new'       => ($jsonEncode) ? json_encode($this->modified) : $this->modified,
469            'state'     => ($jsonEncode) ? json_encode($this->stateData) : $this->stateData,
470            'metadata'  => ($jsonEncode) ? json_encode($this->metadata) : $this->metadata,
471            'timestamp' => date('Y-m-d H:i:s')
472        ];
473    }
474
475    /**
476     * Send the results of the audit
477     *
478     * @return mixed
479     */
480    abstract public function send(): mixed;
481
482    /**
483     * Get model states
484     *
485     * @return array
486     */
487    abstract public function getStates(): array;
488
489    /**
490     * Get model state by ID
491     *
492     * @param  int|string $id
493     * @return array
494     */
495    abstract public function getStateById(int|string $id): array;
496
497    /**
498     * Get model state by model
499     *
500     * @param  string          $model
501     * @param  int|string|null $modelId
502     * @return array
503     */
504    abstract public function getStateByModel(string $model, int|string|null $modelId = null): array;
505
506    /**
507     * Get model state by timestamp
508     *
509     * @param  string  $from
510     * @param  ?string $backTo
511     * @return array
512     */
513    abstract public function getStateByTimestamp(string $from, ?string $backTo = null): array;
514
515    /**
516     * Get model state by date
517     *
518     * @param  string  $from
519     * @param  ?string $backTo
520     * @return array
521     */
522    abstract public function getStateByDate(string $from, ?string $backTo = null): array;
523
524    /**
525     * Get model snapshot by ID
526     *
527     * @param  int|string $id
528     * @param  bool       $post
529     * @return array
530     */
531    abstract public function getSnapshot(int|string $id, bool $post = false): array;
532
533}