Total Complexity | 40 |
Total Lines | 272 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Ivory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Ivory, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | final class Ivory |
||
16 | { |
||
17 | const VERSION = '0.1.0a1'; |
||
18 | |||
19 | /** @var ICoreFactory */ |
||
20 | private static $coreFactory = null; |
||
21 | /** @var TypeRegister */ |
||
22 | private static $typeRegister = null; |
||
23 | /** @var ISqlPatternParser */ |
||
24 | private static $sqlPatternParser = null; |
||
25 | /** @var StatementExceptionFactory */ |
||
26 | private static $stmtExFactory = null; |
||
27 | /** @var IConnection[] map: name => connection */ |
||
28 | private static $connections = []; |
||
29 | /** @var IConnection|null */ |
||
30 | private static $defaultConn = null; |
||
31 | /** @var CacheItemPoolInterface|null */ |
||
32 | private static $defaultCacheImpl = null; |
||
33 | /** @var ICacheControl|null */ |
||
34 | private static $globalCacheControl = null; |
||
35 | /** @var IValueComparator */ |
||
36 | private static $defaultValueComparator = null; |
||
37 | |||
38 | |||
39 | private function __construct() |
||
40 | { |
||
41 | // the class is static - no actual instance is to be used |
||
42 | } |
||
43 | |||
44 | public static function getCoreFactory(): ICoreFactory |
||
45 | { |
||
46 | if (self::$coreFactory === null) { |
||
47 | self::$coreFactory = new StdCoreFactory(); |
||
48 | } |
||
49 | return self::$coreFactory; |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Provides Ivory with a factory for core objects. |
||
54 | * |
||
55 | * Note that {@link Ivory} caches the objects so setting another core factory is only effective at the very |
||
56 | * beginning of working with Ivory. |
||
57 | * |
||
58 | * @param ICoreFactory $coreFactory |
||
59 | */ |
||
60 | public static function setCoreFactory(ICoreFactory $coreFactory): void |
||
61 | { |
||
62 | self::$coreFactory = $coreFactory; |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * Returns the global type register, used for getting types not defined locally for a connection. |
||
67 | */ |
||
68 | public static function getTypeRegister(): TypeRegister |
||
69 | { |
||
70 | if (self::$typeRegister === null) { |
||
71 | self::$typeRegister = self::getCoreFactory()->createGlobalTypeRegister(); |
||
72 | } |
||
73 | return self::$typeRegister; |
||
74 | } |
||
75 | |||
76 | public static function getSqlPatternParser(): ISqlPatternParser |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * Returns the global statement exception factory. |
||
87 | * |
||
88 | * An exception factory is used for emitting {@link \Ivory\Exception\StatementException}s upon statement errors. |
||
89 | * Like the type register, an overriding exception factory is also defined locally on each connection - this factory |
||
90 | * only applies if the local one does not. |
||
91 | */ |
||
92 | public static function getStatementExceptionFactory(): StatementExceptionFactory |
||
93 | { |
||
94 | if (self::$stmtExFactory === null) { |
||
95 | self::$stmtExFactory = self::getCoreFactory()->createStatementExceptionFactory(); |
||
96 | } |
||
97 | return self::$stmtExFactory; |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * @return ICacheControl cache control used globally, independent of any specific connection |
||
102 | */ |
||
103 | public static function getGlobalCacheControl(): ICacheControl |
||
109 | } |
||
110 | |||
111 | /** |
||
112 | * @return CacheItemPoolInterface|null the cache implementation to use for connections which do not set their own |
||
113 | * cache, or <tt>null</tt> if no default cache implementation is set up |
||
114 | */ |
||
115 | public static function getDefaultCacheImpl(): ?CacheItemPoolInterface |
||
116 | { |
||
117 | return self::$defaultCacheImpl; |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * @param CacheItemPoolInterface|null $cacheItemPool the cache implementation to use for connections which do not |
||
122 | * set their own cache, or <tt>null</tt> for no default cache |
||
123 | */ |
||
124 | public static function setDefaultCacheImpl(?CacheItemPoolInterface $cacheItemPool): void |
||
125 | { |
||
126 | self::$defaultCacheImpl = $cacheItemPool; |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Sets up a new database connection. |
||
131 | * |
||
132 | * If this is the first connection to set up, it is automatically set as the default connection. |
||
133 | * |
||
134 | * The connection with the database is not immediately established - just a {@link Connection} object is initialized |
||
135 | * and returned, it connects to the database on demand. |
||
136 | * |
||
137 | * @param mixed $params the parameters for creating the connection; |
||
138 | * anything accepted by {@link ConnectionParameters::create()} - one of the following options: |
||
139 | * <ul> |
||
140 | * <li>a {@link ConnectionParameters} object |
||
141 | * <li>a URI, e.g., <tt>"postgresql://usr@localhost:5433/db?connect_timeout=10"</tt> |
||
142 | * <li>a PostgreSQL connection string, e.g., |
||
143 | * <tt>"host=localhost port=5432 dbname=mydb connect_timeout=10"</tt> |
||
144 | * <li>a map of connection parameter keywords to values, e.g., <tt>['host' => '/tmp']</tt> |
||
145 | * </ul> |
||
146 | * @param string|null $connName name for the connection; |
||
147 | * if not given, the database name is considered if it is given within |
||
148 | * <tt>$params</tt>, or the fallback name <tt>'conn'</tt> is used; |
||
149 | * if not given and if the auto-generated name is already taken, it is appended with a |
||
150 | * numeric suffix, e.g., <tt>'conn1'</tt>, <tt>'conn2'</tt>, etc. |
||
151 | * @return IConnection |
||
152 | * @throws ConnectionException if connection name is explicitly specified but a connection with the same name |
||
153 | * already exists |
||
154 | */ |
||
155 | public static function setupNewConnection($params, ?string $connName = null): IConnection |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * @param string|null $connName name of the connection to get; <tt>null</tt> to get the default connection |
||
191 | * @return IConnection |
||
192 | * @throws \RuntimeException if the default connection is requested but no connection has been setup yet, or if the |
||
193 | * requested connection is not defined |
||
194 | */ |
||
195 | public static function getConnection(?string $connName = null): IConnection |
||
196 | { |
||
197 | if ($connName === null) { |
||
198 | if (self::$defaultConn) { |
||
199 | return self::$defaultConn; |
||
200 | } else { |
||
201 | throw new \RuntimeException('No connection has been setup'); |
||
202 | } |
||
203 | } |
||
204 | |||
205 | if (isset(self::$connections[$connName])) { |
||
206 | return self::$connections[$connName]; |
||
207 | } else { |
||
208 | throw new \RuntimeException("Undefined connection: '$connName'"); |
||
209 | } |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * @param IConnection|string $conn (name of) connection to use as the default connection |
||
214 | * @throws \RuntimeException if the requested connection is not defined |
||
215 | */ |
||
216 | public static function useConnectionAsDefault($conn): void |
||
217 | { |
||
218 | if (is_string($conn)) { |
||
219 | if (isset(self::$connections[$conn])) { |
||
220 | $conn = self::$connections[$conn]; |
||
221 | } else { |
||
222 | throw new \RuntimeException('Undefined connection'); |
||
223 | } |
||
224 | } elseif (!$conn instanceof IConnection) { |
||
225 | throw new \InvalidArgumentException('conn'); |
||
226 | } |
||
227 | |||
228 | self::$defaultConn = $conn; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Removes a connection from the register so that it no longer occupies memory. |
||
233 | * |
||
234 | * Unless instructed otherwise by the `$disconnect` argument, the connection gets closed if still connected. |
||
235 | * |
||
236 | * @param IConnection|string|null $conn (name of) connection to remove from the register; |
||
237 | * <tt>null</tt> to remove the default connection |
||
238 | * @param bool $disconnect if <tt>true</tt>, the connection to database will be closed |
||
239 | * @throw \RuntimeException if the default connection is requested but no connection has been setup yet, or if the |
||
240 | * requested connection is not defined |
||
241 | */ |
||
242 | public static function dropConnection($conn = null, bool $disconnect = true): void |
||
267 | } |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * @return IValueComparator value comparator to use as the default one |
||
272 | */ |
||
273 | public static function getDefaultValueComparator(): IValueComparator |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * Discards the default value comparator, cached by {@link getDefaultValueComparator()}. |
||
283 | */ |
||
284 | public static function flushDefaultValueComparator(): void |
||
285 | { |
||
286 | self::$defaultValueComparator = null; |
||
287 | } |
||
288 | } |
||
289 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.