/[drupal]/contributions/modules/migrator/migrator.module
ViewVC logotype

Contents of /contributions/modules/migrator/migrator.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Mon Apr 28 18:30:53 2008 UTC (18 months, 3 weeks ago) by sun
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +14 -9 lines
File MIME type: text/x-php
Added variable to switch db connection only when necessary.
1 <?php
2 // $Id: migrator.module,v 1.1 2008/04/14 05:43:41 sun Exp $
3
4 /**
5 * @file
6 * Core functions and Drupal hook implementations for Migrator.
7 *
8 * Pre-requisites:
9 * - migrator_get_* functions need to return data always in the same schema or
10 * structure like the equivalent Drupal function. This also includes object
11 * properties, f.e. of contents or users.
12 *
13 * @todo Add system feature 'node'?
14 * @todo Add button to reset migrator settings + mappings (excluding DB config).
15 * @todo Add DB column 'created' to support incremental migrations.
16 *
17 * Flow:
18 * - Install data mapping table. [DONE]
19 * - Setup database connection, user roles mappings, user mappings. [DONE]
20 * - Enable migration modules.
21 * - Only modules installed on remote system are displayed.
22 * - One module may support different targets (f.e. Privatemsg, Buddy Chat).
23 * - Example: UddeIM (Joomla) -> Privatemsg.
24 * - Remote system contents need to be supported via migration modules, too.
25 * - Configure migration modules (f.e. node import target content-types/fields).
26 * - Import users.
27 * - Assigning them to configured user roles.
28 * - Import sections, categories into taxonomy.
29 * - Import static contents into pages.
30 * - Import contents into stories.
31 * - Import CB user profiles into Bio contents.
32 * - Import forum contents into forum posts/comments.
33 */
34
35 /**
36 * Implementation of hook_perm().
37 */
38 function migrator_perm() {
39 return array('administer migrator');
40 }
41
42 /**
43 * Implementation of hook_menu().
44 */
45 function migrator_menu($may_cache) {
46 $items = array();
47 $access = user_access('administer migrator');
48 if ($may_cache) {
49 // Replace with introduction + help page later.
50 $items[] = array(
51 'path' => 'admin/settings/migrator',
52 'title' => t('Migrator'),
53 'callback' => 'drupal_get_form',
54 'callback arguments' => 'migrator_settings_system',
55 'access' => $access,
56 );
57 $items[] = array(
58 'path' => 'admin/settings/migrator/settings',
59 'title' => t('Settings'),
60 'callback' => 'drupal_get_form',
61 'callback arguments' => 'migrator_settings_system',
62 'access' => $access,
63 'type' => MENU_DEFAULT_LOCAL_TASK,
64 'weight' => -10,
65 );
66 $items[] = array(
67 'path' => 'admin/settings/migrator/migrate',
68 'title' => t('Migrate'),
69 'callback' => 'migrator_migrate',
70 'access' => $access,
71 'type' => MENU_LOCAL_TASK,
72 );
73 }
74 else {
75 // Load Migrator include files.
76 foreach (glob(drupal_get_path('module', 'migrator') .'/*.inc') as $include) {
77 require_once $include;
78 }
79 // Load Migrator remote system migration includes.
80 if (migrator_system()) {
81 foreach (glob(drupal_get_path('module', 'migrator') .'/'. migrator_system() .'/*.inc') as $include) {
82 include_once $include;
83 }
84 }
85
86 $items[] = array(
87 'path' => 'admin/settings/migrator/settings/system',
88 'title' => t('System'),
89 'access' => $access,
90 'type' => MENU_DEFAULT_LOCAL_TASK,
91 'weight' => -10,
92 );
93 foreach (migrator_system_features() as $feature => $item) {
94 if (isset($item['#dependencies'])) {
95 foreach ($item['#dependencies'] as $module) {
96 if (!module_exists($module)) {
97 continue 2;
98 }
99 }
100 }
101 $items[] = array(
102 'path' => 'admin/settings/migrator/settings/'. $feature,
103 'title' => drupal_ucfirst($feature),
104 'callback' => 'drupal_get_form',
105 'callback arguments' => 'migrator_settings_'. $feature,
106 'access' => $access,
107 'type' => MENU_LOCAL_TASK,
108 );
109 }
110 // Autocomplete callback for object mappings forms.
111 $items[] = array(
112 'path' => 'admin/settings/migrator/autocomplete',
113 'callback' => 'migrator_autocomplete',
114 'type' => MENU_CALLBACK,
115 'access' => $access,
116 );
117 // Delete callback for object mappings.
118 $items[] = array(
119 'path' => 'admin/settings/migrator/delete',
120 'callback' => 'migrator_map_del',
121 'type' => MENU_CALLBACK,
122 'access' => $access,
123 );
124 }
125 return $items;
126 }
127
128 /**
129 * Return variable migrator_system.
130 */
131 function migrator_system() {
132 static $system;
133
134 if (!isset($system)) {
135 $system = variable_get('migrator_system', '');
136 }
137 return $system;
138 }
139
140 /**
141 * Return available features of remote system.
142 */
143 function migrator_system_features() {
144 $features = array(
145 'modules' => array(),
146 );
147 $function = 'migrator_'. migrator_system() .'_system';
148 if (function_exists($function)) {
149 $features = array_merge($features, $function());
150 }
151 return $features;
152 }
153
154 /**
155 * Return whether remote system supports a given feature.
156 */
157 function migrator_system_has_feature($feature) {
158 $features = migrator_system_features();
159 return isset($features[$feature]);
160 }
161
162 /**
163 * Connect to remote system database.
164 *
165 * @see migrator_db_disconnect(), migrator_get()
166 */
167 function migrator_db_connect() {
168 global $db_url, $db_prefix;
169 if (migrator_system_has_feature('database') && migrator_db_is_valid()) {
170 if (!variable_get('migrator_db_is_default', TRUE)) {
171 $migrator_db_url = variable_get('migrator_db', '');
172 if (!is_array($db_url)) {
173 $db_url = array('default' => $db_url);
174 }
175 if (!empty($migrator_db_url)) {
176 $db_url['migrator'] = $migrator_db_url;
177 db_set_active('migrator');
178 }
179 }
180 migrator_get_default_db_prefix();
181 $db_prefix = variable_get('migrator_db_prefix', 'jos_');
182 }
183 }
184
185 /**
186 * Disconnect from remote system database.
187 *
188 * @see migrator_db_connect(), migrator_get()
189 */
190 function migrator_db_disconnect() {
191 if (migrator_system_has_feature('database') && migrator_db_is_valid()) {
192 if (!variable_get('migrator_db_is_default', TRUE)) {
193 db_set_active();
194 }
195 migrator_set_default_db_prefix();
196 }
197 }
198
199 /**
200 * Helper function to recall Drupal's default database table prefix.
201 *
202 * @see migrator_set_default_prefix()
203 */
204 function migrator_get_default_db_prefix() {
205 global $db_prefix;
206 static $drupal_db_prefix;
207 if (!isset($drupal_db_prefix)) {
208 $drupal_db_prefix = $db_prefix;
209 }
210 return $drupal_db_prefix;
211 }
212
213 /**
214 * Helper function to reset Drupal's default database table prefix.
215 *
216 * @see migrator_get_default_prefix()
217 */
218 function migrator_set_default_db_prefix() {
219 global $db_prefix;
220 $db_prefix = migrator_get_default_db_prefix();
221 }
222
223 /**
224 * Check if a configured remote system database connection is valid.
225 *
226 * @see migrator_settings_system()
227 */
228 function migrator_db_is_valid() {
229 $db = parse_url(variable_get('migrator_db', ''));
230 if (!empty($db['scheme']) && !empty($db['host']) && !empty($db['user']) && !empty($db['pass']) && !empty($db['path'])) {
231 return TRUE;
232 }
233 return FALSE;
234 }
235
236 /**
237 * Check if remote system supports a database and it has been setup.
238 */
239 function migrator_check_db() {
240 if (migrator_system_has_feature('database') && !migrator_db_is_valid()) {
241 drupal_set_message(t('Missing database configuration. Please setup remote system database connection first.'));
242 drupal_goto('admin/settings/migrator/settings/database');
243 }
244 }
245
246 /**
247 * Return a remote system object specific database key (column name).
248 *
249 * @param string $object
250 * A system object.
251 *
252 * @return string
253 * An aliased SQL query column name, f.e. 'u.uid' for object 'user'.
254 */
255 function migrator_key($object) {
256 $function = 'migrator_'. migrator_system() .'_key';
257 if (!function_exists($function)) {
258 return FALSE;
259 }
260 return $function($object);
261 }
262
263 /**
264 * Generic database callback for querying pre-defined data from remote system.
265 *
266 * @param string $op
267 * The get-operation to perform in the remote system.
268 */
269 function migrator_get($op) {
270 $function = 'migrator_get_'. migrator_system() .'_'. $op;
271 if (!function_exists($function)) {
272 return FALSE;
273 }
274 migrator_db_connect();
275 $args = func_get_args();
276 array_shift($args);
277 $result = call_user_func_array($function, $args);
278 migrator_db_disconnect();
279 return $result;
280 }
281
282 /**
283 * Retrieve custom mappings for a given object type from the database.
284 *
285 * @param string $object
286 * An object name, f.e. 'role'.
287 * @param bool $all
288 * Whether to also return non-custom mappings for the given object type.
289 *
290 * @return array
291 * An array of custom mappings, keyed by remote system id.
292 *
293 * @see migrator_map_set(), migrator_map_del()
294 */
295 function migrator_map_get($object, $all = FALSE) {
296 $mappings = array();
297 if (!$all) {
298 $custom = ' AND custom = 1';
299 }
300 $result = db_query("SELECT id_old, id_new FROM {migrator_map} WHERE object = '%s'". $custom, $object);
301 while ($map = db_fetch_array($result)) {
302 $mappings[$map['id_old']] = $map['id_new'];
303 }
304 return $mappings;
305 }
306
307 /**
308 * Save custom mappings to the database.
309 *
310 * @param string $object
311 * A system object/feature.
312 * @param array $mappings
313 * An associative array of local/remote object mappings.
314 * @param bool $reset
315 * Whether to delete all existing mappings before inserting new mappings.
316 *
317 * @see migrator_map_get(), migrator_map_del()
318 */
319 function migrator_map_set($object, $mappings = array(), $reset = FALSE) {
320 if ($reset) {
321 db_query("DELETE FROM {migrator_map} WHERE object = '%s' AND custom = 1", $object);
322 }
323 foreach ($mappings as $old => $new) {
324 migrator_map_add($object, $old, $new, TRUE);
325 }
326 drupal_set_message(t('The configuration has been saved.'));
327 }
328
329 /**
330 * Add a new mapping for migrated object to the database.
331 *
332 * Don't use this function for custom mappings, use migrator_map_set() instead.
333 * This function is called heavily during migration.
334 *
335 * @param string $object
336 * A system object/feature.
337 * @param int $old
338 * An old object id of remote system.
339 * @param int $old
340 * A new object id of Drupal.
341 * @param bool $custom
342 * Whether a custom mapping is added.
343 *
344 * @see migrator_map_set()
345 */
346 function migrator_map_add($object, $old, $new, $custom = FALSE) {
347 return db_query("INSERT INTO {migrator_map} (object, id_old, id_new, custom) VALUES ('%s', %d, %d, %d)", $object, $old, $new, (int)$custom);
348 }
349
350 /**
351 * Delete a custom mapping.
352 *
353 * @param string $object
354 * A system object/feature.
355 * @param int $rid
356 * A remote system object id mapping.
357 *
358 * @see migrator_map_get(), migrator_map_set(), migrator_map_del_all()
359 */
360 function migrator_map_del($object, $rid) {
361 db_query("DELETE FROM {migrator_map} WHERE object = '%s' AND id_old = %d AND custom = 1", $object, $rid);
362 drupal_set_message(t('The mapping has been deleted.'));
363 drupal_goto(referer_uri());
364 }
365
366 /**
367 * Delete all non-custom mappings.
368 *
369 * @see migrator_map_del()
370 */
371 function migrator_map_del_all() {
372 db_query("DELETE FROM {migrator_map} WHERE custom = 0");
373 }
374
375 /**
376 * Invoke migration.
377 *
378 * @todo Ensure a backup is present (Demo).
379 * @todo Define migration order in remote system definition.
380 */
381 function migrator_migrate() {
382 // Remove non-custom mappings.
383 migrator_map_del_all();
384
385 // Load Migrator remote system migration includes.
386 foreach (glob(drupal_get_path('module', 'migrator') .'/modules/*.inc') as $include) {
387 require_once $include;
388 }
389
390 // Migrate users.
391 $remote_users = migrator_get('users');
392 foreach ($remote_users as $uid => $user) {
393 migrator_create_user($user);
394 }
395
396 drupal_set_message(t('Migration has been completed.'));
397 drupal_goto('admin/settings/migrator');
398 }
399
400 /**
401 * Retrieve a pipe delimited string of autocomplete suggestions.
402 */
403 function migrator_autocomplete($object, $string = '') {
404 $matches = migrator_get('autocomplete_'. $object, $string);
405 print drupal_to_js($matches);
406 exit();
407 }
408
409 /**
410 * Quick access to remote system database.
411 * // unused 12/04/2008 sun
412 *
413 * @see db_query()
414 */
415 function migrator_db_query($query) {
416 migrator_db_connect();
417
418 $args = func_get_args();
419 array_shift($args);
420 $query = db_prefix_tables($query);
421 if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
422 $args = $args[0];
423 }
424 _db_query_callback($args, TRUE);
425 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
426 $result = _db_query($query);
427
428 migrator_db_disconnect();
429 return $result;
430 }
431
432

  ViewVC Help
Powered by ViewVC 1.1.2