Total Complexity | 42 |
Total Lines | 305 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like setup_cmd_database 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 setup_cmd_database, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class setup_cmd_database extends setup_cmd |
||
19 | { |
||
20 | /** |
||
21 | * Allow to run this command via setup-cli |
||
22 | */ |
||
23 | const SETUP_CLI_CALLABLE = true; |
||
24 | |||
25 | /** |
||
26 | * Maximum length of database name (at least for MySQL this is the limit) |
||
27 | * |
||
28 | * @var int |
||
29 | */ |
||
30 | const MAX_DB_NAME_LEN = 16; |
||
31 | |||
32 | /** |
||
33 | * Instance of Api\Db to connect or create the db |
||
34 | * |
||
35 | * @var Api\Db |
||
36 | */ |
||
37 | private $test_db; |
||
38 | |||
39 | /** |
||
40 | * Constructor |
||
41 | * |
||
42 | * @param string/array $domain domain-name to customize the defaults or array with all parameters |
||
|
|||
43 | * @param string $db_type db-type (mysql, pgsql, ...) |
||
44 | * @param string $db_host =null |
||
45 | * @param string $db_port =null |
||
46 | * @param string $db_name =null |
||
47 | * @param string $db_user =null |
||
48 | * @param string $db_pass =null |
||
49 | * @param string $db_root =null |
||
50 | * @param string $db_root_pw =null |
||
51 | * @param string $sub_command ='create_db' 'create_db', 'test_db', 'test_db_root' |
||
52 | * @param string $db_grant_host ='localhost' host/ip of webserver for grant |
||
53 | * @param boolean $make_db_name_unique =false true: if create fails because db exists, |
||
54 | * try creating a unique name by shortening the name and adding a number to it |
||
55 | */ |
||
56 | function __construct($domain,$db_type=null,$db_host=null,$db_port=null,$db_name=null,$db_user=null,$db_pass=null, |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * run the command: test or create database |
||
86 | * |
||
87 | * @param boolean $check_only =false only run the checks (and throw the exceptions), but not the command itself |
||
88 | * @return string success message |
||
89 | * @throws Exception(lang('Wrong credentials to access the header.inc.php file!'),2); |
||
90 | * @throws Exception('header.inc.php not found!'); |
||
91 | */ |
||
92 | protected function exec($check_only=false) |
||
93 | { |
||
94 | if (!empty($this->domain) && !preg_match('/^([a-z0-9_-]+\.)*[a-z0-9]+/i',$this->domain)) |
||
95 | { |
||
96 | throw new Api\Exception\WrongUserinput(lang("'%1' is no valid domain name!",$this->domain)); |
||
97 | } |
||
98 | if ($this->remote_id && $check_only) return true; // further checks can only done locally |
||
99 | |||
100 | $this->_merge_defaults(); |
||
101 | //_debug_array($this->as_array()); |
||
102 | |||
103 | try { |
||
104 | switch($this->sub_command) |
||
105 | { |
||
106 | case 'test_db_root': |
||
107 | $msg = $this->connect($this->db_root,$this->db_root_pw,$this->db_meta); |
||
108 | break; |
||
109 | case 'test_db': |
||
110 | $msg = $this->connect(); |
||
111 | break; |
||
112 | case 'drop': |
||
113 | $msg = $this->drop(); |
||
114 | break; |
||
115 | case 'create_db': |
||
116 | default: |
||
117 | $msg = $this->create(); |
||
118 | break; |
||
119 | } |
||
120 | } |
||
121 | catch (Exception $e) { |
||
122 | // we catch the exception to properly restore the db |
||
123 | } |
||
124 | $this->restore_db(); |
||
125 | |||
126 | if ($e) |
||
127 | { |
||
128 | throw $e; |
||
129 | } |
||
130 | return $msg; |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * Connect to database |
||
135 | * |
||
136 | * @param string $user =null default $this->db_user |
||
137 | * @param string $pass =null default $this->db_pass |
||
138 | * @param string $name =null default $this->db_name |
||
139 | * @throws Api\Exception\WrongUserinput Can not connect to database ... |
||
140 | */ |
||
141 | private function connect($user=null,$pass=null,$name=null) |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * Check and if does not yet exist create the new database and user |
||
167 | * |
||
168 | * The check will fail if the database exists, but already contains tables |
||
169 | * |
||
170 | * if $this->make_db_name_unique is set, a decrementing nummeric prefix gets |
||
171 | * added to $this->db_name AND $this->db_user, if db already exists. |
||
172 | * |
||
173 | * @return string with success message |
||
174 | * @throws Api\Exception\WrongUserinput |
||
175 | */ |
||
176 | private function create() |
||
177 | { |
||
178 | static $try_make_unique = 0; // to limit trials to create a unique name |
||
179 | |||
180 | // shorten db-name/-user to self::MAX_DB_NAME_LEN chars |
||
181 | if ($this->make_db_name_unique && strlen($this->db_name) > self::MAX_DB_NAME_LEN) |
||
182 | { |
||
183 | $this->set_defaults['db_name'] = $this->db_name = |
||
184 | $this->set_defaults['db_user'] = $this->db_user = // change user too (otherwise existing user/db could not connect any more!) |
||
185 | substr(str_replace(array('.', '-'), '_', $this->db_name),0,self::MAX_DB_NAME_LEN); |
||
186 | } |
||
187 | try { |
||
188 | $msg = $this->connect(); |
||
189 | } |
||
190 | catch (Api\Exception\WrongUserinput $e) { |
||
191 | // db or user not working --> connect as root and create it |
||
192 | try { |
||
193 | $this->test_db->create_database($this->db_root,$this->db_root_pw,$this->db_charset,$this->db_grant_host); |
||
194 | $this->connect(); |
||
195 | } |
||
196 | catch(Api\Db\Exception $e) { // catches failed to create database |
||
197 | // try connect as root to check if wrong root/root_pw is the problem |
||
198 | $this->connect($this->db_root,$this->db_root_pw,$this->db_meta); |
||
199 | |||
200 | // if we should create a db with a unique name (try it only N times, not endless!) |
||
201 | if ($this->make_db_name_unique && $try_make_unique++ < 20) |
||
202 | { |
||
203 | // check if we can connect as root to the db to create --> db exists already |
||
204 | try { |
||
205 | $this->connect($this->db_root,$this->db_root_pw); |
||
206 | // create new db_name by incrementing an existing numeric postfix |
||
207 | $matches = null; |
||
208 | if (preg_match('/([0-9]+)$/',$this->db_name,$matches)) |
||
209 | { |
||
210 | $num = (string)(++$matches[1]); |
||
211 | } |
||
212 | else // or adding one starting with 2 |
||
213 | { |
||
214 | $num = '2'; |
||
215 | } |
||
216 | $this->set_defaults['db_name'] = $this->db_name = |
||
217 | $this->set_defaults['db_user'] = $this->db_user = // change user too (otherwise existing user/db could not connect any more!) |
||
218 | substr($this->db_name,0,self::MAX_DB_NAME_LEN-strlen($num)).$num; |
||
219 | |||
220 | return $this->create(); |
||
221 | } |
||
222 | catch (Api\Exception\WrongUserinput $e2) |
||
223 | { |
||
224 | // we can NOT connect to db as root --> ignore exception to give general error |
||
225 | } |
||
226 | } |
||
227 | // if not give general error |
||
228 | throw new Api\Exception\WrongUserinput(lang('Can not create %1 database %2 on %3 for user %4!', |
||
229 | $this->db_type,$this->db_name,$this->db_host.($this->db_port?':'.$this->db_port:''),$this->db_user)); |
||
230 | } |
||
231 | $msg = lang('Successful connected to %1 on %3 and created database %2 for user %4.', |
||
232 | $this->db_type,$this->db_name,$this->db_host.($this->db_port?':'.$this->db_port:''),$this->db_user); |
||
233 | } |
||
234 | // check if it already contains tables |
||
235 | if (($tables = $this->test_db->table_names())) |
||
236 | { |
||
237 | foreach($tables as &$table) |
||
238 | { |
||
239 | $table = $table['table_name']; |
||
240 | } |
||
241 | throw new Api\Exception\WrongUserinput(lang('%1 database %2 on %3 already contains the following tables:', |
||
242 | $this->db_type,$this->db_name,$this->db_host.($this->db_port?':'.$this->db_port:'')).' '. |
||
243 | implode(', ',$tables)); |
||
244 | } |
||
245 | return $msg; |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Drop database and user |
||
250 | * |
||
251 | * @return string with success message |
||
252 | * @throws Api\Exception\WrongUserinput |
||
253 | * @throws Api\Db\Exception if database not exist |
||
254 | */ |
||
255 | private function drop() |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * Return default database settings for a given domain |
||
274 | * |
||
275 | * @param string $db_type ='mysqli' |
||
276 | * @return array |
||
277 | */ |
||
278 | static function defaults($db_type='mysqli') |
||
279 | { |
||
280 | switch($db_type) |
||
281 | { |
||
282 | case 'mysql': |
||
283 | default: |
||
284 | $db_type = $meta_db = 'mysql'; |
||
285 | break; |
||
286 | case 'pgsql': |
||
287 | $meta_db = 'template1'; |
||
288 | break; |
||
289 | } |
||
290 | return array( |
||
291 | 'db_type' => $db_type, |
||
292 | 'db_host' => 'localhost', |
||
293 | 'db_port' => 3306, |
||
294 | 'db_name' => 'egw_$domain', |
||
295 | 'db_user' => 'egw_$domain', |
||
296 | 'db_pass' => self::randomstring(), |
||
297 | 'db_root' => 'root', |
||
298 | 'db_root_pw' => '', // not really a default |
||
299 | 'db_meta' => $meta_db, |
||
300 | 'db_charset' => 'utf-8', |
||
301 | 'db_grant_host' => 'localhost', |
||
302 | ); |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * Merges the default into the current properties, if they are empty or contain placeholders |
||
307 | */ |
||
308 | private function _merge_defaults() |
||
323 | } |
||
324 | } |
||
325 | } |
||
326 | } |
||
327 |