Lines 28.44% 33 / 116
Methods 36.00% 9 / 25
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 0.00% 0 / 19 0.00% 0 / 1 20
 __call 0.00% 0 / 6 0.00% 0 / 1 20
 postConnect 0.00% 0 / 1 0.00% 0 / 1 2
 loadAccessor 0.00% 0 / 8 0.00% 0 / 1 12
 connect n/a 0 / 0 n/a 0 / 0 0
 requirePdo 0.00% 0 / 3 0.00% 0 / 1 6
 getConnection 0.00% 0 / 1 0.00% 0 / 1 2
 query 0.00% 0 / 3 0.00% 0 / 1 6
 exec 0.00% 0 / 3 0.00% 0 / 1 6
 prepare 0.00% 0 / 3 0.00% 0 / 1 6
 beginTransaction 0.00% 0 / 6 0.00% 0 / 1 12
 commit 0.00% 0 / 8 0.00% 0 / 1 30
 rollBack 0.00% 0 / 8 0.00% 0 / 1 30
 inTransaction 0.00% 0 / 3 0.00% 0 / 1 6
 [BO\Zmsdldb\AbstractAccess] addAccessInstanceLocale 0.00% 0 / 2 0.00% 0 / 1 6
 [BO\Zmsdldb\AbstractAccess] getInstanceCompatibilities 100.00% 9 / 9 100.00% 1 / 1 1
 [BO\Zmsdldb\AbstractAccess] getInstanceOnName 100.00% 4 / 4 100.00% 1 / 1 3
 [BO\Zmsdldb\AbstractAccess] from 46.15% 6 / 13 0.00% 0 / 1 11.62
 [BO\Zmsdldb\AbstractAccess] fromAuthority 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsdldb\AbstractAccess] fromBorough 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsdldb\AbstractAccess] fromLink 0.00% 0 / 2 0.00% 0 / 1 2
 [BO\Zmsdldb\AbstractAccess] fromLocation 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsdldb\AbstractAccess] fromOffice 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsdldb\AbstractAccess] fromService 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsdldb\AbstractAccess] fromSetting 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsdldb\AbstractAccess] fromTopic 100.00% 2 / 2 100.00% 1 / 1 1
5abstract class PDOAccess extends AbstractAccess
6{
7    /**
8     * @SuppressWarnings(PHPMD.LongVariable)
9     */
10    protected mixed $accessorClassName = [];
11
12    protected array $accessorNamesPlural = [
13        'Authority' => 'Authorities',
14        'Borough' => 'Boroughs',
15        'Link' => 'Links',
16        'Location' => 'Locations',
17        'Office' => 'Offices',
18        'Service' => 'Services',
19        'Setting' => 'Settings',
20        'Topic' => 'Topics'
21    ];
22
23    protected ?\PDO $pdo = null;
24
25    protected string $engine = 'SQLite';
26
27
28    public function __construct(array $options)
29    {
30        try {
31            $parts = explode("\\", static::class);
32            $this->engine = str_replace('Access', '', end($parts));
33
34            $accessorNameKeys = array_keys($this->accessorNamesPlural);
35            $accessorClassName = array_flip($this->accessorNamesPlural);
36
37            $this->accessorClassName = array_merge(
38                $accessorClassName,
39                array_combine($accessorNameKeys, $accessorNameKeys)
40            );
41            $this->accessorNamesPlural = array_merge(
42                $this->accessorNamesPlural,
43                array_flip($this->accessorNamesPlural)
44            );
45
46            if (isset($options['pdoConnection']) && $options['pdoConnection'] instanceof \PDO) {
47                $this->pdo = $options['pdoConnection'];
48            } else {
49                $this->connect($options);
50            }
51            $this->requirePdo()->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
52            $this->postConnect();
53        } catch (\Exception $e) {
54            throw $e;
55        }
56    }
57
58    #[\Override]
59    public function __call(mixed $method, array $args = [])
60    {
61        try {
62            return parent::__call($method, $args);
63        } catch (\Exception $e) {
64            if ('loadFromPath' != $method && preg_match('/load(?P<accessor>[A-Za-z_0-9]+)/', $method, $matches)) {
65                $locale = $args[0] ?? 'de';
66                $instance = $this->loadAccessor($matches['accessor'], $locale);
67
68                return $instance;
69            }
70        }
71    }
72
73    /**
74     * @return void
75     */
76    protected function postConnect()
77    {
78    }
79
80    public function loadAccessor(string $name, string $locale = 'de'): mixed
81    {
82        if (isset($this->accessorClassName[$name])) {
83            if (null === $this->accessInstance[$locale][$this->accessorClassName[$name]]) {
84                $accessorClass = __NAMESPACE__ . '\\' . $this->engine . '\\' . $this->accessorClassName[$name];
85
86                /** @var class-string $accessorClass */
87                $instance = new $accessorClass($this, $locale);
88                $this->accessInstance[$locale][$name] = $instance;
89                $this->accessInstance[$locale][$this->accessorNamesPlural[$name]] = $instance;
90            }
91            return $this->accessInstance[$locale][$name];
92        }
93        throw new \Exception('Invalid accessor');
94    }
95
96    abstract protected function connect(array $options): void;
97
98    protected function requirePdo(): \PDO
99    {
100        if (!$this->pdo instanceof \PDO) {
101            throw new \RuntimeException('PDO connection is not initialized');
102        }
103        return $this->pdo;
104    }
105
106    /** @psalm-api */
107    public function getConnection(): mixed
108    {
109        return $this->pdo;
110    }
111
112    /**
113     * parameters see https://www.php.net/manual/de/pdo.query.php
114     */
115
116    public function query(mixed ...$args): mixed
117    {
118        try {
119            return $this->requirePdo()->query(...$args);
120        } catch (\Exception $e) {
121            throw $e;
122        }
123    }
124
125    /**
126     * parameters see https://www.php.net/manual/de/pdo.exec.php
127     */
128    public function exec(string ...$args): mixed
129    {
130        try {
131            return $this->requirePdo()->exec(...$args);
132        } catch (\Exception $e) {
133            throw $e;
134        }
135    }
136
137    /**
138     * parameters see https://www.php.net/manual/de/pdo.prepare.php
139     */
140    public function prepare(mixed ...$args): mixed
141    {
142        try {
143            return $this->requirePdo()->prepare(...$args);
144        } catch (\Exception $e) {
145            throw $e;
146        }
147    }
148
149    protected int $transactionCount = 0;
150
151    public function beginTransaction(): mixed
152    {
153        try {
154            $this->transactionCount++;
155            if ($this->inTransaction()) {
156                return true;
157            }
158            return $this->requirePdo()->beginTransaction();
159        } catch (\Exception $e) {
160            throw $e;
161        }
162    }
163
164    public function commit(): mixed
165    {
166        try {
167            $this->transactionCount--;
168            if ($this->transactionCount == 0 && $this->inTransaction()) {
169                return $this->requirePdo()->commit();
170            } elseif (!$this->inTransaction()) {
171                trigger_error(__METHOD__ . ' no transaction started');
172            }
173            return true;
174        } catch (\Exception $e) {
175            throw $e;
176        }
177    }
178
179    public function rollBack(): mixed
180    {
181        try {
182            $this->transactionCount--;
183            if ($this->transactionCount == 0 && $this->inTransaction()) {
184                return $this->requirePdo()->rollBack();
185            } elseif (!$this->inTransaction()) {
186                trigger_error(__METHOD__ . ' no transaction started');
187            }
188            return true;
189        } catch (\Exception $e) {
190            throw $e;
191        }
192    }
193
194    public function inTransaction(): mixed
195    {
196        try {
197            return $this->requirePdo()->inTransaction();
198        } catch (\Exception $e) {
199            throw $e;
200        }
201    }
202}

Inherited from BO\Zmsdldb\AbstractAccess

54    public function addAccessInstanceLocale(string $locale = 'de'): void
55    {
56        if (!isset($this->accessInstance[$locale])) {
57            $this->accessInstance[$locale] = static::$accessInstanceTypes;
58        }
59    }
62    private function getInstanceCompatibilities(): mixed
63    {
64        $accessInstance = $this->accessInstance['de'];
65        $accessInstance['Authorities'] = $accessInstance['Authority'];
66        $accessInstance['Boroughs'] = $accessInstance['Borough'];
67        $accessInstance['Offices'] = $accessInstance['Office'];
68        $accessInstance['Settings'] = $accessInstance['Setting'];
69        $accessInstance['Topics'] = $accessInstance['Topic'];
70        $accessInstance['Locations'] = $accessInstance['Location'];
71        $accessInstance['Services'] = $accessInstance['Service'];
72        return $accessInstance;
73    }
128    protected function getInstanceOnName(mixed $name, int $position = 0)
129    {
130        foreach (array_keys($this->getInstanceCompatibilities()) as $instanceName) {
131            if ($position === strpos($name, $instanceName)) {
132                return $instanceName;
133            }
134        }
135        return null;
136    }
138    protected function from(string $instanceName, string $locale = 'de'): File\Base
139    {
140        if (array_key_exists($instanceName, $this->accessInstance[$locale])) {
141            $instance = $this->accessInstance[$locale][$instanceName];
142            if ($instance instanceof \BO\Zmsdldb\File\Base) {
143                return $instance;
144            }
145            if (null === $instance) {
146                throw new Exception("Instance for accessing $instanceName ($locale) is not initialized");
147            }
148            throw new Exception("Instance for accessing $instanceName failed");
149        }
150        if (class_exists('\App', false) && isset(\App::$log)) {
151            \App::$log->error('DLDB access locale missing', [
152                'instance' => $instanceName,
153                'locale' => $locale,
154            ]);
155        }
156        throw new Exception("Locale for accessing $instanceName does not exists");
157    }
159    public function fromAuthority(string $locale = 'de'): File\Authority
160    {
161        /** @var File\Authority $instance */
162        $instance = $this->from('Authority', $locale);
163        return $instance;
164    }
166    public function fromBorough(): File\Borough
167    {
168        /** @var File\Borough $instance */
169        $instance = $this->from('Borough');
170        return $instance;
171    }
174    public function fromLink(string $locale = 'de'): File\Link
175    {
176        /** @var File\Link $instance */
177        $instance = $this->from('Link', $locale);
178        return $instance;
179    }
181    public function fromLocation(string $locale = 'de'): File\Location
182    {
183        /** @var File\Location $instance */
184        $instance = $this->from('Location', $locale);
185        return $instance;
186    }
188    public function fromOffice(): File\Office
189    {
190        /** @var File\Office $instance */
191        $instance = $this->from('Office');
192        return $instance;
193    }
195    public function fromService(string $locale = 'de'): File\Service
196    {
197        /** @var File\Service $instance */
198        $instance = $this->from('Service', $locale);
199        return $instance;
200    }
202    public function fromSetting(): File\Setting
203    {
204        /** @var File\Setting $instance */
205        $instance = $this->from('Setting');
206        return $instance;
207    }
209    public function fromTopic(string $locale = 'de'): File\Topic
210    {
211        /** @var File\Topic $instance */
212        $instance = $this->from('Topic', $locale);
213        return $instance;
214    }