Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
72 / 72
100.00% covered (success)
100.00%
11 / 11
CRAP
100.00% covered (success)
100.00%
1 / 1
Table
100.00% covered (success)
100.00%
72 / 72
100.00% covered (success)
100.00%
11 / 11
27
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 setTable
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getTable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 send
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 getStates
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getStateById
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 getStateByModel
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getStateByTimestamp
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getStateByDate
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 getSnapshot
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
 createTable
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
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
16use Pop\Db\Record;
17
18/**
19 * Auditor table class
20 *
21 * @category   Pop
22 * @package    Pop\Audit
23 * @author     Nick Sagona, III <dev@nolainteractive.com>
24 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
25 * @license    http://www.popphp.org/license     New BSD License
26 * @version    2.0.0
27 */
28class Table extends AbstractAdapter
29{
30
31    /**
32     * Table class name
33     * @var ?string
34     */
35    protected ?string $table = null;
36
37    /**
38     * Constructor
39     *
40     * Instantiate the table adapter object
41     *
42     * @param  string $table
43     */
44    public function __construct(string $table)
45    {
46        $this->setTable($table);
47        $db        = call_user_func($this->table . '::getDb');
48        $tableName = call_user_func($this->table . '::table');
49
50        if (!($db->hasTable($tableName))) {
51            $this->createTable($tableName);
52        }
53    }
54
55    /**
56     * Set the table
57     *
58     * @param  string $table
59     * @return Table
60     */
61    public function setTable(string $table): Table
62    {
63        $this->table = $table;
64        return $this;
65    }
66
67    /**
68     * Get the table
69     *
70     * @return string
71     */
72    public function getTable(): string
73    {
74        return $this->table;
75    }
76
77    /**
78     * Send the results of the audit
79     *
80     * @throws Exception
81     * @return Record
82     */
83    public function send(): Record
84    {
85        if ($this->action === null) {
86            throw new Exception('The model state differences have not been resolved.');
87        }
88        if (($this->model === null) || ($this->modelId === null)) {
89            throw new Exception('The model has not been set.');
90        }
91
92        $className = $this->table;
93        $table     = new $className($this->prepareData());
94        $table->save();
95
96        return $table;
97    }
98
99    /**
100     * Get model states
101     *
102     * @param  ?array $columns
103     * @param  ?array $options
104     * @return array
105     */
106    public function getStates(?array $columns = null, ?array $options = null): array
107    {
108        if ($columns !== null) {
109            $result = call_user_func_array($this->table . '::findBy', ['columns' => $columns, 'options' => $options]);
110        } else {
111            $result = call_user_func_array($this->table . '::findAll', ['options' => $options]);
112        }
113
114        return $result->toArray();
115    }
116
117    /**
118     * Get model state by ID
119     *
120     * @param  int|string $id
121     * @return array
122     */
123    public function getStateById(int|string $id): array
124    {
125        $record = call_user_func_array($this->table . '::findById', ['id' => $id]);
126        $result = $record->toArray();
127
128        if (!empty($result['old'])) {
129            $result['old'] = json_decode($result['old'], true);
130        }
131        if (!empty($result['new'])) {
132            $result['new'] = json_decode($result['new'], true);
133        }
134
135        return $result;
136    }
137
138    /**
139     * Get model state by model
140     *
141     * @param  string          $model
142     * @param  int|string|null $modelId
143     * @param  array           $columns
144     * @return array
145     */
146    public function getStateByModel(string $model, int|string|null $modelId = null, array $columns = []): array
147    {
148        $columns['model']    = $model;
149        if ($modelId !== null) {
150            $columns['model_id'] = $modelId;
151        }
152        $result = call_user_func_array($this->table . '::findBy', [$columns]);
153        return $result->toArray();
154    }
155
156    /**
157     * Get model state by timestamp
158     *
159     * @param  string  $from
160     * @param  ?string $backTo
161     * @param  array   $columns
162     * @return array
163     */
164    public function getStateByTimestamp(string $from, ?string $backTo = null, array $columns = []): array
165    {
166        $columns['timestamp<='] = date('Y-m-d H:i:s', $from);
167        if ($backTo !== null) {
168            $columns['timestamp>='] = date('Y-m-d H:i:s', $backTo);
169        }
170        $result = call_user_func_array($this->table . '::findBy', [$columns]);
171        return $result->toArray();
172    }
173
174    /**
175     * Get model state by date
176     *
177     * @param  string  $from
178     * @param  ?string $backTo
179     * @param  array   $columns
180     * @return array
181     */
182    public function getStateByDate(string $from, ?string $backTo = null, array $columns = []): array
183    {
184        if (!str_contains($from, ' ')) {
185            $from .= ' 23:59:59';
186        }
187        $columns['timestamp<='] = $from;
188        if ($backTo !== null) {
189            if (!str_contains($backTo, ' ')) {
190                $backTo .= ' 00:00:00';
191            }
192            $columns['timestamp>='] = $backTo;
193        }
194        $result = call_user_func_array($this->table . '::findBy', [$columns]);
195        return $result->toArray();
196    }
197
198    /**
199     * Get model snapshot by ID
200     *
201     * @param  int|string $id
202     * @param  bool       $post
203     * @return array
204     */
205    public function getSnapshot(int|string $id, bool $post = false): array
206    {
207        $result   = call_user_func_array($this->table . '::findById', ['id' => $id]);
208        $snapshot = [];
209
210        if (!($post) && !empty($result->old)) {
211            $snapshot = json_decode($result->old, true);
212        } else if (($post) && !empty($result->new)) {
213            $snapshot = json_decode($result->new, true);
214        }
215
216        return $snapshot;
217    }
218
219    /**
220     * Create table in database
221     *
222     * @param  string $tableName
223     * @return void
224     */
225    protected function createTable(string $tableName): void
226    {
227        $db     = call_user_func($this->table . '::getDb');
228        $schema = $db->createSchema();
229        $schema->create($tableName)
230            ->int('id')->increment()
231            ->int('user_id')
232            ->varchar('username', 255)
233            ->varchar('domain', 255)
234            ->varchar('route', 255)
235            ->varchar('method', 255)
236            ->varchar('model', 255)->notNullable()
237            ->int('model_id')->notNullable()
238            ->varchar('action', 255)->notNullable()
239            ->text('old')
240            ->text('new')
241            ->text('state')
242            ->text('metadata')
243            ->datetime('timestamp')->notNullable()
244            ->primary('id');
245
246        $db->query($schema);
247    }
248
249}