37
Clayton Parker, Senior Developer Migrating From Drupal to Plone with Transmogrifier PLONE SYMPOSIUM EAST 2011

Migrating from drupal to plone with transmogrifier

Embed Size (px)

DESCRIPTION

Transmogrifier is a migration framework that can help you easily migrate from one platform to another. It has been written in a way that allows re-use of migration code through blueprints. In this talk we will walk through the steps necessary to migrate from Drupal, a popular CMS written in PHP, into Plone. We will see how to use the various blueprints available to build a pipeline that prepares and imports the content into Plone

Citation preview

Page 1: Migrating from drupal to plone with transmogrifier

Clayton Parker, Senior Developer

Migrating From Drupal to Plone with Transmogrifier

PLONE SYMPOSIUM EAST 2011

Page 2: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Who Am I?

• claytron

• Python dev since 2003

• Plone Core Committer

• Foundation Member

Page 3: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011What will we learn?

• Transmogrifier basics

• Migration Planning Process

• Creating a pipeline

Page 4: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Migrations

• One off scripts

• In multiple places

• Little to no re-usability

Page 5: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Transmogrifier

• A framework for migrations

• Re-usable parts

Page 6: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Basics

• Pipeline

• Blueprints

• Sources

• Section

Page 7: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Sources

• A blueprint

• First item in your pipeline

Page 8: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011

<html><body><h3>Code Sample</h3><p>Replace this text!</p></body></html>

Example Pipeline[transmogrifier]pipeline = csv_file constructor schemaupdater

[csv_file]blueprint = collective.transmogrifier.sections.csvsourcefilename = my.migration.import:my_items.csv

[constructor]blueprint = collective.transmogrifier.sections.constructor

[schemaupdater]blueprint = plone.app.transmogrifier.atschemaupdater

Page 9: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011my_items.csv

_path , _type , title , description/folder1 , Folder , First Folder , This is folder One/folder2 , Folder , Second Folder , This is folder Two/folder1/foo , Document , One Foo , A document named foo/folder2/foo , Document , Two Foo , Another doc named foo

Page 10: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011The Result

Page 11: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Items

• Each item is a mapping

• Keys are fields

• Keys with a leading underscore are controllers

Page 12: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Example Item{'_id': 'a-stronger-connection-to-out-customers', '_path': 'content/stronger-connection-out-customers', '_status': 1L, '_text_mimetype': 'text/html', '_transitions': 'publish', '_type': 'Document', 'allowDiscussion': False, 'creation_date': '2011/05/14 9:20:50', 'effectiveDate': '2011/05/14 9:20:50', 'modification_date': '2011/05/18 9:22:22', 'subject': 'better\ninteresting\nstronger', 'text': '<p>this is some text</p>\r\n', 'title': 'A stronger connection to out customers'}

Page 13: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Migration Strategy

• Investigate the source

• Prepare the destination

• Find Transmogrifier blueprints

• Write the pipeline

Page 14: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Write your own

• Missing blueprint

• Write one

• Contribute it back

Page 15: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011GenericSetup

• Make migration part of your release

• Ability to package migrations

Page 16: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011My Migration

• Drupal backed by MySQL

• transmogrify.sqlalchemy

• Plone 4.0.5

• collective.blog.star

• plone.app.discussion

Page 17: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Package Layoutmy.migration!"" my#   !"" __init__.py#   %"" migration#   !"" __init__.py#   !"" config#   #   !"" articles.cfg#   #   !"" base.cfg#   #   !"" blogs.cfg#   #   !"" comments.cfg#   #   %"" pages.cfg#   !"" configure.zcml#   %"" profiles#      %"" default#      !"" metadata.xml#      %"" transmogrifier.txt!"" setup.cfg%"" setup.py

Page 18: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Registering Configs

<transmogrifier:registerConfig name="my.migration.base" title="My migration base config" description="Base settings for all transmogrifier imports" configuration="config/base.cfg" />

Page 19: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Registering Configs

<transmogrifier:registerConfig name="my.migration.pages" title="Drupal pages" description="Import pages from Drupal into Plone" configuration="config/pages.cfg" />

Page 20: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Registering Configs

<transmogrifier:registerConfig name="my.migration.articles" title="Drupal articles" description="Import articles from Drupal into Plone" configuration="config/articles.cfg" />

Page 21: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Registering Configs

<transmogrifier:registerConfig name="my.migration.blogs" title="Drupal blog entries" description="Import blog entries from Drupal into Plone" configuration="config/blogs.cfg" />

Page 22: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Registering Configs

<transmogrifier:registerConfig name="my.migration.comments" title="Drupal comments" description="Import comments from Drupal into Plone" configuration="config/comments.cfg" />

Page 23: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011transmogrifier.txt

my.migration.pagesmy.migration.articlesmy.migration.blogsmy.migration.comments

Page 24: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Package Layoutmy.migration!"" my#   !"" __init__.py#   %"" migration#   !"" __init__.py#   !"" config#   #   !"" articles.cfg#   #   !"" base.cfg#   #   !"" blogs.cfg#   #   !"" comments.cfg#   #   %"" pages.cfg#   !"" configure.zcml#   %"" profiles#      %"" default#      !"" metadata.xml#      %"" transmogrifier.txt!"" setup.cfg%"" setup.py

Page 25: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011base.cfg pipeline[transmogrifier]pipeline = drupal portal_type url_normalizer path publication_state text_mimetype mimetype_encapsulator folders constructor commenting comments schema_update workflow reindex_object

[settings]# Path to use if there isn’t one givenbase_path = other-content# Have to escape python string formatting for when # this gets passed into sqlalchemydate_format = %%Y/%%m/%%d %%k:%%i:%%s

Page 26: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011drupal section

[drupal]blueprint = transmogrify.sqlalchemydsn = mysql://user:password@localhost/drupal-transmog

Page 27: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011articles.cfg[transmogrifier]include = my.migration.base

[drupal]query = SELECT node.title, node.status AS status, GROUP_CONCAT(tag_data.name SEPARATOR '\n') AS subject, FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date, FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate, FROM_UNIXTIME(node.changed, "${settings:date_format}") AS modification_date, body_data.body_value AS text url_alias.alias AS _path FROM node INNER JOIN field_data_field_tags AS tag_field ON tag_field.entity_id = node.nid INNER JOIN taxonomy_term_data AS tag_data ON tag_data.tid = tag_field.field_tags_tid INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) GROUP BY node.title, node.status, node.created, node.changed, body_data.body_value, url_alias.alias;

[portal_type]value = string:Document

Page 28: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011pages.cfg[transmogrifier]include = my.migration.base

[drupal]query = my.migration.base SELECT node.title, node.status AS _status, FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date, FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate, FROM_UNIXTIME(node.changed, "${settings:date_format}") AS modification_date, body_data.body_value AS text, url_alias.alias AS _path FROM node INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) WHERE node.type = "page" GROUP BY node.title, node.status, node.created, node.changed, body_data.body_value, url_alias.alias;

[portal_type]value = string:Document

Page 29: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011blogs.cfg[transmogrifier]include = my.migration.base

[drupal]query = SELECT node.title, node.satus AS _status, FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date, FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate, FROM_UNIXTIME(node.created, "${settings:date_format}") AS modification_date, body_data.body_value AS text, url_alias.alias AS _path FROM node INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) WHERE node.type = "blog" GROUP BY node.title, node.status, node.created, node.changed, body_data.body_value, url_alias.alias;

[portal_type]value = string:BlogEntry

[commenting]value = python:True

Page 30: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011comments.cfg[transmogrifier]include = my.migration.base

[drupal]query = my.migration.base SELECT comment.subject AS title, FROM_UNIXTIME(comment.created, "${settings:date_format}") AS published, FROM_UNIXTIME(comment.changed, "${settings:date_format}") AS updated, comment.name AS author_name, body_data.comment_body_value AS text, url_alias.alias AS _parent_path FROM comment INNER JOIN field_data_comment_body AS body_data ON body_data.entity_id = comment.cid INNER JOIN node ON node.nid = comment.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) GROUP BY comment.subject, comment.created, comment.changed, comment.name, body_data.comment_body_value, url_alias.alias;

[portal_type]# Override the portal type to use the "comment_type"key = string:_comment_typevalue = string:plone.app.discussion

Page 31: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011base.cfg overrides[path]blueprint = collective.transmogrifier.sections.inserter# only add a path if one does not existcondition = python:'_path' not in item and not '_parent_path' in itemkey = string:_path# Add the value in the extended configurationvalue = string:${settings:base_path}/${item/_id}

[portal_type]blueprint = collective.transmogrifier.sections.inserterkey = string:_type# We will add the value in the extended config, but we need a# default set herevalue = string:

[commenting]blueprint = collective.transmogrifier.sections.inserterkey = string:allowDiscussion# default to falsevalue = python:False

Page 32: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Content Creation

[comments]blueprint = transmogrify.comments

[folders]blueprint = collective.transmogrifier.sections.folders

[constructor]blueprint = collective.transmogrifier.sections.constructor

[schema_update]blueprint = plone.app.transmogrifier.atschemaupdater

[workflow]blueprint = plone.app.transmogrifier.workflowupdater

[reindex_object]blueprint = plone.app.transmogrifier.reindexobject

Page 33: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Item Modification[publication_state]blueprint = collective.transmogrifier.sections.insertercondition = python:'_status' in item and item['_status'] == 1key = string:_transitionsvalue = string:publish

[text_mimetype]# This could probably be taken from the database as wellblueprint = collective.transmogrifier.sections.inserterkey = string:_text_mimetypevalue = string:text/html

[mimetype_encapsulator]blueprint = plone.app.transmogrifier.mimeencapsulatorkey = textmimetype = python:item.get('_%s_mimetype', key)field = keycondition = mimetype

Page 34: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011

DEMO

Page 35: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Links

• collective.transmogrifier

http://pypi.python.org/pypi/collective.transmogrifier/

• plone.app.transmogrifier

http://pypi.python.org/pypi/plone.app.transmogrifier/

Page 36: Migrating from drupal to plone with transmogrifier

PLONE SYMPOSIUM EAST 2011Useful Sources and Blueprints• plone.app.transmogrifier

• transmogrify.filesystem

• transmogrify.sqlalchemy

• transmogrify.webcrawler

• quintagroup.transmogrifier

• transmogrify.comments

Page 37: Migrating from drupal to plone with transmogrifier

Check out

sixfeetup.com/demos