1 <?php
2 /**
3 * @package Joomla.Platform
4 * @subpackage Database
5 *
6 * @copyright Copyright (C) 2005 - 2017 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 * Joomla Platform Database Importer Class
14 *
15 * @since 12.1
16 */
17 abstract class JDatabaseImporter
18 {
19 /**
20 * @var array An array of cached data.
21 * @since 13.1
22 */
23 protected $cache = array();
24
25 /**
26 * The database connector to use for exporting structure and/or data.
27 *
28 * @var JDatabaseDriver
29 * @since 13.1
30 */
31 protected $db = null;
32
33 /**
34 * The input source.
35 *
36 * @var mixed
37 * @since 13.1
38 */
39 protected $from = array();
40
41 /**
42 * The type of input format (XML).
43 *
44 * @var string
45 * @since 13.1
46 */
47 protected $asFormat = 'xml';
48
49 /**
50 * An array of options for the exporter.
51 *
52 * @var object
53 * @since 13.1
54 */
55 protected $options = null;
56
57 /**
58 * Constructor.
59 *
60 * Sets up the default options for the exporter.
61 *
62 * @since 13.1
63 */
64 public function __construct()
65 {
66 $this->options = new stdClass;
67
68 $this->cache = array('columns' => array(), 'keys' => array());
69
70 // Set up the class defaults:
71
72 // Import with only structure
73 $this->withStructure();
74
75 // Export as XML.
76 $this->asXml();
77
78 // Default destination is a string using $output = (string) $exporter;
79 }
80
81 /**
82 * Set the output option for the exporter to XML format.
83 *
84 * @return JDatabaseImporter Method supports chaining.
85 *
86 * @since 13.1
87 */
88 public function asXml()
89 {
90 $this->asFormat = 'xml';
91
92 return $this;
93 }
94
95 /**
96 * Checks if all data and options are in order prior to exporting.
97 *
98 * @return JDatabaseImporter Method supports chaining.
99 *
100 * @since 13.1
101 * @throws Exception if an error is encountered.
102 */
103 abstract public function check();
104
105 /**
106 * Specifies the data source to import.
107 *
108 * @param mixed $from The data source to import.
109 *
110 * @return JDatabaseImporter Method supports chaining.
111 *
112 * @since 13.1
113 */
114 public function from($from)
115 {
116 $this->from = $from;
117
118 return $this;
119 }
120
121 /**
122 * Get the SQL syntax to drop a column.
123 *
124 * @param string $table The table name.
125 * @param string $name The name of the field to drop.
126 *
127 * @return string
128 *
129 * @since 13.1
130 */
131 protected function getDropColumnSql($table, $name)
132 {
133 return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP COLUMN ' . $this->db->quoteName($name);
134 }
135
136 /**
137 * Get the real name of the table, converting the prefix wildcard string if present.
138 *
139 * @param string $table The name of the table.
140 *
141 * @return string The real name of the table.
142 *
143 * @since 13.1
144 */
145 protected function getRealTableName($table)
146 {
147 $prefix = $this->db->getPrefix();
148
149 // Replace the magic prefix if found.
150 $table = preg_replace('|^#__|', $prefix, $table);
151
152 return $table;
153 }
154
155 /**
156 * Merges the incoming structure definition with the existing structure.
157 *
158 * @return void
159 *
160 * @note Currently only supports XML format.
161 * @since 13.1
162 * @throws RuntimeException on error.
163 */
164 public function mergeStructure()
165 {
166 $prefix = $this->db->getPrefix();
167 $tables = $this->db->getTableList();
168
169 if ($this->from instanceof SimpleXMLElement)
170 {
171 $xml = $this->from;
172 }
173 else
174 {
175 $xml = new SimpleXMLElement($this->from);
176 }
177
178 // Get all the table definitions.
179 $xmlTables = $xml->xpath('database/table_structure');
180
181 foreach ($xmlTables as $table)
182 {
183 // Convert the magic prefix into the real table name.
184 $tableName = (string) $table['name'];
185 $tableName = preg_replace('|^#__|', $prefix, $tableName);
186
187 if (in_array($tableName, $tables))
188 {
189 // The table already exists. Now check if there is any difference.
190 if ($queries = $this->getAlterTableSql($xml->database->table_structure))
191 {
192 // Run the queries to upgrade the data structure.
193 foreach ($queries as $query)
194 {
195 $this->db->setQuery((string) $query);
196 $this->db->execute();
197 }
198 }
199 }
200 else
201 {
202 // This is a new table.
203 $sql = $this->xmlToCreate($table);
204
205 $this->db->setQuery((string) $sql);
206 $this->db->execute();
207 }
208 }
209 }
210
211 /**
212 * Sets the database connector to use for exporting structure and/or data.
213 *
214 * @param JDatabaseDriver $db The database connector.
215 *
216 * @return JDatabaseImporter Method supports chaining.
217 *
218 * @since 13.1
219 */
220 public function setDbo(JDatabaseDriver $db)
221 {
222 $this->db = $db;
223
224 return $this;
225 }
226
227 /**
228 * Sets an internal option to merge the structure based on the input data.
229 *
230 * @param boolean $setting True to export the structure, false to not.
231 *
232 * @return JDatabaseImporter Method supports chaining.
233 *
234 * @since 13.1
235 */
236 public function withStructure($setting = true)
237 {
238 $this->options->withStructure = (boolean) $setting;
239
240 return $this;
241 }
242 }
243