Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
mysqli.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Database
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 /**
13  * MySQLi import driver.
14  *
15  * @package Joomla.Platform
16  * @subpackage Database
17  * @since 11.1
18  */
20 {
21  /**
22  * Checks if all data and options are in order prior to exporting.
23  *
24  * @return JDatabaseImporterMysqli Method supports chaining.
25  *
26  * @since 11.1
27  * @throws Exception if an error is encountered.
28  */
29  public function check()
30  {
31  // Check if the db connector has been set.
32  if (!($this->db instanceof JDatabaseDriverMysqli))
33  {
34  throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
35  }
36 
37  // Check if the tables have been specified.
38  if (empty($this->from))
39  {
40  throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
41  }
42 
43  return $this;
44  }
45 
46  /**
47  * Get the SQL syntax to add a column.
48  *
49  * @param string $table The table name.
50  * @param SimpleXMLElement $field The XML field definition.
51  *
52  * @return string
53  *
54  * @since 11.1
55  */
56  protected function getAddColumnSQL($table, SimpleXMLElement $field)
57  {
58  return 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD COLUMN ' . $this->getColumnSQL($field);
59  }
60 
61  /**
62  * Get the SQL syntax to add a key.
63  *
64  * @param string $table The table name.
65  * @param array $keys An array of the fields pertaining to this key.
66  *
67  * @return string
68  *
69  * @since 11.1
70  */
71  protected function getAddKeySQL($table, $keys)
72  {
73  return 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD ' . $this->getKeySQL($keys);
74  }
75 
76  /**
77  * Get alters for table if there is a difference.
78  *
79  * @param SimpleXMLElement $structure The XML structure pf the table.
80  *
81  * @return array
82  *
83  * @since 11.1
84  */
85  protected function getAlterTableSQL(SimpleXMLElement $structure)
86  {
87  $table = $this->getRealTableName($structure['name']);
88  $oldFields = $this->db->getTableColumns($table);
89  $oldKeys = $this->db->getTableKeys($table);
90  $alters = array();
91 
92  // Get the fields and keys from the XML that we are aiming for.
93  $newFields = $structure->xpath('field');
94  $newKeys = $structure->xpath('key');
95 
96  // Loop through each field in the new structure.
97  foreach ($newFields as $field)
98  {
99  $fName = (string) $field['Field'];
100 
101  if (isset($oldFields[$fName]))
102  {
103  // The field exists, check it's the same.
104  $column = $oldFields[$fName];
105 
106  // Test whether there is a change.
107  $change = ((string) $field['Type'] != $column->Type) || ((string) $field['Null'] != $column->Null)
108  || ((string) $field['Default'] != $column->Default) || ((string) $field['Extra'] != $column->Extra);
109 
110  if ($change)
111  {
112  $alters[] = $this->getChangeColumnSQL($table, $field);
113  }
114 
115  // Unset this field so that what we have left are fields that need to be removed.
116  unset($oldFields[$fName]);
117  }
118  else
119  {
120  // The field is new.
121  $alters[] = $this->getAddColumnSQL($table, $field);
122  }
123  }
124 
125  // Any columns left are orphans
126  foreach ($oldFields as $name => $column)
127  {
128  // Delete the column.
129  $alters[] = $this->getDropColumnSQL($table, $name);
130  }
131 
132  // Get the lookups for the old and new keys.
133  $oldLookup = $this->getKeyLookup($oldKeys);
134  $newLookup = $this->getKeyLookup($newKeys);
135 
136  // Loop through each key in the new structure.
137  foreach ($newLookup as $name => $keys)
138  {
139  // Check if there are keys on this field in the existing table.
140  if (isset($oldLookup[$name]))
141  {
142  $same = true;
143  $newCount = count($newLookup[$name]);
144  $oldCount = count($oldLookup[$name]);
145 
146  // There is a key on this field in the old and new tables. Are they the same?
147  if ($newCount == $oldCount)
148  {
149  // Need to loop through each key and do a fine grained check.
150  for ($i = 0; $i < $newCount; $i++)
151  {
152  $same = (((string) $newLookup[$name][$i]['Non_unique'] == $oldLookup[$name][$i]->Non_unique)
153  && ((string) $newLookup[$name][$i]['Column_name'] == $oldLookup[$name][$i]->Column_name)
154  && ((string) $newLookup[$name][$i]['Seq_in_index'] == $oldLookup[$name][$i]->Seq_in_index)
155  && ((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation)
156  && ((string) $newLookup[$name][$i]['Index_type'] == $oldLookup[$name][$i]->Index_type));
157 
158  /*
159  Debug.
160  echo '<pre>';
161  echo '<br />Non_unique: '.
162  ((string) $newLookup[$name][$i]['Non_unique'] == $oldLookup[$name][$i]->Non_unique ? 'Pass' : 'Fail').' '.
163  (string) $newLookup[$name][$i]['Non_unique'].' vs '.$oldLookup[$name][$i]->Non_unique;
164  echo '<br />Column_name: '.
165  ((string) $newLookup[$name][$i]['Column_name'] == $oldLookup[$name][$i]->Column_name ? 'Pass' : 'Fail').' '.
166  (string) $newLookup[$name][$i]['Column_name'].' vs '.$oldLookup[$name][$i]->Column_name;
167  echo '<br />Seq_in_index: '.
168  ((string) $newLookup[$name][$i]['Seq_in_index'] == $oldLookup[$name][$i]->Seq_in_index ? 'Pass' : 'Fail').' '.
169  (string) $newLookup[$name][$i]['Seq_in_index'].' vs '.$oldLookup[$name][$i]->Seq_in_index;
170  echo '<br />Collation: '.
171  ((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation ? 'Pass' : 'Fail').' '.
172  (string) $newLookup[$name][$i]['Collation'].' vs '.$oldLookup[$name][$i]->Collation;
173  echo '<br />Index_type: '.
174  ((string) $newLookup[$name][$i]['Index_type'] == $oldLookup[$name][$i]->Index_type ? 'Pass' : 'Fail').' '.
175  (string) $newLookup[$name][$i]['Index_type'].' vs '.$oldLookup[$name][$i]->Index_type;
176  echo '<br />Same = '.($same ? 'true' : 'false');
177  echo '</pre>';
178  */
179 
180  if (!$same)
181  {
182  // Break out of the loop. No need to check further.
183  break;
184  }
185  }
186  }
187  else
188  {
189  // Count is different, just drop and add.
190  $same = false;
191  }
192 
193  if (!$same)
194  {
195  $alters[] = $this->getDropKeySQL($table, $name);
196  $alters[] = $this->getAddKeySQL($table, $keys);
197  }
198 
199  // Unset this field so that what we have left are fields that need to be removed.
200  unset($oldLookup[$name]);
201  }
202  else
203  {
204  // This is a new key.
205  $alters[] = $this->getAddKeySQL($table, $keys);
206  }
207  }
208 
209  // Any keys left are orphans.
210  foreach ($oldLookup as $name => $keys)
211  {
212  if (strtoupper($name) == 'PRIMARY')
213  {
214  $alters[] = $this->getDropPrimaryKeySQL($table);
215  }
216  else
217  {
218  $alters[] = $this->getDropKeySQL($table, $name);
219  }
220  }
221 
222  return $alters;
223  }
224 
225  /**
226  * Get the syntax to alter a column.
227  *
228  * @param string $table The name of the database table to alter.
229  * @param SimpleXMLElement $field The XML definition for the field.
230  *
231  * @return string
232  *
233  * @since 11.1
234  */
235  protected function getChangeColumnSQL($table, SimpleXMLElement $field)
236  {
237  return 'ALTER TABLE ' . $this->db->quoteName($table) . ' CHANGE COLUMN ' . $this->db->quoteName((string) $field['Field']) . ' '
238  . $this->getColumnSQL($field);
239  }
240 
241  /**
242  * Get the SQL syntax for a single column that would be included in a table create or alter statement.
243  *
244  * @param SimpleXMLElement $field The XML field definition.
245  *
246  * @return string
247  *
248  * @since 11.1
249  */
250  protected function getColumnSQL(SimpleXMLElement $field)
251  {
252  // TODO Incorporate into parent class and use $this.
253  $blobs = array('text', 'smalltext', 'mediumtext', 'largetext');
254 
255  $fName = (string) $field['Field'];
256  $fType = (string) $field['Type'];
257  $fNull = (string) $field['Null'];
258  $fDefault = isset($field['Default']) ? (string) $field['Default'] : null;
259  $fExtra = (string) $field['Extra'];
260 
261  $query = $this->db->quoteName($fName) . ' ' . $fType;
262 
263  if ($fNull == 'NO')
264  {
265  if (in_array($fType, $blobs) || $fDefault === null)
266  {
267  $query .= ' NOT NULL';
268  }
269  else
270  {
271  // TODO Don't quote numeric values.
272  $query .= ' NOT NULL DEFAULT ' . $this->db->quote($fDefault);
273  }
274  }
275  else
276  {
277  if ($fDefault === null)
278  {
279  $query .= ' DEFAULT NULL';
280  }
281  else
282  {
283  // TODO Don't quote numeric values.
284  $query .= ' DEFAULT ' . $this->db->quote($fDefault);
285  }
286  }
287 
288  if ($fExtra)
289  {
290  $query .= ' ' . strtoupper($fExtra);
291  }
292 
293  return $query;
294  }
295 
296  /**
297  * Get the SQL syntax to drop a key.
298  *
299  * @param string $table The table name.
300  * @param string $name The name of the key to drop.
301  *
302  * @return string
303  *
304  * @since 11.1
305  */
306  protected function getDropKeySQL($table, $name)
307  {
308  return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP KEY ' . $this->db->quoteName($name);
309  }
310 
311  /**
312  * Get the SQL syntax to drop a key.
313  *
314  * @param string $table The table name.
315  *
316  * @return string
317  *
318  * @since 11.1
319  */
320  protected function getDropPrimaryKeySQL($table)
321  {
322  return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP PRIMARY KEY';
323  }
324 
325  /**
326  * Get the details list of keys for a table.
327  *
328  * @param array $keys An array of objects that comprise the keys for the table.
329  *
330  * @return array The lookup array. array({key name} => array(object, ...))
331  *
332  * @since 11.1
333  * @throws Exception
334  */
335  protected function getKeyLookup($keys)
336  {
337  // First pass, create a lookup of the keys.
338  $lookup = array();
339 
340  foreach ($keys as $key)
341  {
342  if ($key instanceof SimpleXMLElement)
343  {
344  $kName = (string) $key['Key_name'];
345  }
346  else
347  {
348  $kName = $key->Key_name;
349  }
350 
351  if (empty($lookup[$kName]))
352  {
353  $lookup[$kName] = array();
354  }
355 
356  $lookup[$kName][] = $key;
357  }
358 
359  return $lookup;
360  }
361 
362  /**
363  * Get the SQL syntax for a key.
364  *
365  * @param array $columns An array of SimpleXMLElement objects comprising the key.
366  *
367  * @return string
368  *
369  * @since 11.1
370  */
371  protected function getKeySQL($columns)
372  {
373  // TODO Error checking on array and element types.
374 
375  $kNonUnique = (string) $columns[0]['Non_unique'];
376  $kName = (string) $columns[0]['Key_name'];
377  $kColumn = (string) $columns[0]['Column_name'];
378 
379  $prefix = '';
380 
381  if ($kName == 'PRIMARY')
382  {
383  $prefix = 'PRIMARY ';
384  }
385  elseif ($kNonUnique == 0)
386  {
387  $prefix = 'UNIQUE ';
388  }
389 
390  $nColumns = count($columns);
391  $kColumns = array();
392 
393  if ($nColumns == 1)
394  {
395  $kColumns[] = $this->db->quoteName($kColumn);
396  }
397  else
398  {
399  foreach ($columns as $column)
400  {
401  $kColumns[] = (string) $column['Column_name'];
402  }
403  }
404 
405  $query = $prefix . 'KEY ' . ($kName != 'PRIMARY' ? $this->db->quoteName($kName) : '') . ' (' . implode(',', $kColumns) . ')';
406 
407  return $query;
408  }
409 }