Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
94.00% |
47 / 50 |
|
62.50% |
5 / 8 |
CRAP | |
0.00% |
0 / 1 |
| DriverBase | |
94.00% |
47 / 50 |
|
62.50% |
5 / 8 |
19.08 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| dispatch | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
| addConnection | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
| changeConnection | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
| setOptions | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
| setLogger | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setQueryOptions | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
| processRecords | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
| formatRecords | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
8.01 | |||
| processOptions | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
| parseOptions | |
85.71% |
6 / 7 |
|
0.00% |
0 / 1 |
3.03 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Projom\Storage\Engine\Driver; |
| 6 | |
| 7 | use Projom\Storage\Query\Action; |
| 8 | use Projom\Storage\Engine\Driver\Connection\ConnectionInterface; |
| 9 | use Projom\Storage\Query\Format; |
| 10 | use Projom\Storage\Query\RecordInterface; |
| 11 | use Psr\Log\LoggerAwareInterface; |
| 12 | use Psr\Log\LoggerInterface; |
| 13 | use Psr\Log\NullLogger; |
| 14 | |
| 15 | abstract class DriverBase implements LoggerAwareInterface |
| 16 | { |
| 17 | protected const DEFAULT_OPTIONS = [ |
| 18 | 'return_single_record' => false, |
| 19 | ]; |
| 20 | |
| 21 | protected LoggerInterface $logger; |
| 22 | private array $options = []; |
| 23 | private null|array $queryOptions = null; |
| 24 | |
| 25 | public function __construct(LoggerInterface $logger = new NullLogger(), array $options = []) |
| 26 | { |
| 27 | $this->logger = $logger; |
| 28 | $this->setOptions($options); |
| 29 | } |
| 30 | |
| 31 | abstract public function dispatch(Action $action, mixed $args): mixed; |
| 32 | abstract public function addConnection(ConnectionInterface $connection): void; |
| 33 | abstract public function changeConnection(int|string $name): void; |
| 34 | |
| 35 | public function setOptions(array $options): void |
| 36 | { |
| 37 | $this->logger->debug( |
| 38 | 'Method: {method} with {options}.', |
| 39 | ['options' => $options, 'method' => __METHOD__] |
| 40 | ); |
| 41 | |
| 42 | $this->options = $options; |
| 43 | } |
| 44 | |
| 45 | public function setLogger(LoggerInterface $logger): void |
| 46 | { |
| 47 | $this->logger = $logger; |
| 48 | } |
| 49 | |
| 50 | protected function setQueryOptions(null|array $queryOptions): void |
| 51 | { |
| 52 | $this->logger->debug( |
| 53 | 'Method: {method} with {options}.', |
| 54 | ['options' => $queryOptions, 'method' => __METHOD__] |
| 55 | ); |
| 56 | |
| 57 | $this->queryOptions = $queryOptions; |
| 58 | } |
| 59 | |
| 60 | protected function processRecords(array $records, array $formatting): mixed |
| 61 | { |
| 62 | $this->logger->debug( |
| 63 | 'Method: {method} with {records}.', |
| 64 | ['records' => $records, 'method' => __METHOD__] |
| 65 | ); |
| 66 | |
| 67 | $records = $this->formatRecords($records, ...$formatting); |
| 68 | $records = $this->processOptions($records); |
| 69 | |
| 70 | return $records; |
| 71 | } |
| 72 | |
| 73 | private function formatRecords(array $records, Format $format, mixed $args = null): mixed |
| 74 | { |
| 75 | $this->logger->debug( |
| 76 | 'Method: {method} with {format} and {args}.', |
| 77 | ['format' => $format->name, 'args' => $args, 'method' => __METHOD__] |
| 78 | ); |
| 79 | |
| 80 | switch ($format) { |
| 81 | case Format::ARRAY: |
| 82 | return $records; |
| 83 | |
| 84 | case Format::STD_CLASS: |
| 85 | return array_map(fn($record) => (object) $record, $records); |
| 86 | |
| 87 | case Format::CUSTOM_OBJECT: |
| 88 | $className = $args; |
| 89 | |
| 90 | if ($className === null) |
| 91 | throw new \Exception('Class name not provided.', 400); |
| 92 | if (!class_exists($className)) |
| 93 | throw new \Exception("Class: $className does not exist.", 400); |
| 94 | if (!is_subclass_of($className, RecordInterface::class)) |
| 95 | throw new \Exception("Class: $className must implement RecordInterface.", 400); |
| 96 | |
| 97 | return array_map(fn($record) => $className::createFromRecord($record), $records); |
| 98 | |
| 99 | default: |
| 100 | throw new \Exception('Format is not recognized.', 400); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | private function processOptions(array $records): array|object |
| 105 | { |
| 106 | $options = $this->parseOptions(); |
| 107 | |
| 108 | if ($options['return_single_record']) |
| 109 | if (count($records) === 1) |
| 110 | $records = $records[0]; |
| 111 | |
| 112 | return $records; |
| 113 | } |
| 114 | |
| 115 | private function parseOptions(): array |
| 116 | { |
| 117 | $parseOptions = $this->options; |
| 118 | if ($this->queryOptions !== null) |
| 119 | $parseOptions = $this->queryOptions; |
| 120 | |
| 121 | $options = static::DEFAULT_OPTIONS; |
| 122 | |
| 123 | if (array_key_exists('return_single_record', $parseOptions)) |
| 124 | $options['return_single_record'] = (bool) $parseOptions['return_single_record']; |
| 125 | |
| 126 | return $options; |
| 127 | } |
| 128 | } |