import and export and the chapter module?

Aug 15, 2011 at 8:38 PM

I want to use the Chapter module from the gallery and be able to import and export my chapter content using the Import Export module. I have not been able to re-create chapter module content using export and import of the Chapter module data.

First, does this work? or does the Chapter module not implement the functions need for import export? If the Chapter module is out of date for import and export, can someone please point me to some documentation on how to make a module support import/export?

Second, what content types do I need to export form the Chapter module to be able to recreate a whole book? I've been selecting for export the content types: Book, Chapter, TableOfContents, and the unique content type representing my book's chapters (for my book called "First Book" this type is "FirstBookChapter"). I've also been exporting metadata and data. The XML file created by export looks like it has all my chapter content. However, when I import the content into a different Orchard instance, the Book is created but the chapters are not.

Any suggestions?

Aug 15, 2011 at 8:47 PM

Yes, Chapters is out of date ... If you want a real good example you should look at how the Taxonomy module is implementing it. There are the same concepts actually : Taxonomy > Book, Term > Chapter. Terms are also hierarchical, so the Chapters can use the same techniques.

Can you give it a try ? A might help you if you need or if you are blocked. I am sorry I did not find the time to do it yet. You can start looking at TermPartDriver and TaxonomyPartDriver which should contain both Import and Export functions.
You might also want to do it as a Fork on this project, so I can embed what you have done in the project.


Aug 16, 2011 at 8:53 PM

Ok, I'm giving it a try and I did run into a roadblock. The TermPartRecord in Taxomony is a little simpler than the ChapterPartRecord in Chapters. The ChapterPartRecord has-a Book which is-a ContentItemRecord. So the ChapterPartRecord contains a reference to the full Book object that is its parent rather than just keeping an ID for the book. This makes importing much more complex becuase in the ChapterPartDriver you need to reinstantiate the Book that is referenced. 

I looked at other examples and I didn't see any other classes that derive from ContentPartRecord that do anything this complex.

I think the best approach is to change the definition of ChapterPartRecord so it just has-a BookId instead of an entire book object reference.

Is this a good approach?

Aug 16, 2011 at 8:57 PM

No, you shouldn't do it, because then it would be harder to create queries ... dead loop.

Actually it's fairly easy to import/export. In the export, just save the BookId as a property. You will see it doesn't save the db id, but an identifier which can be specific. Here it will be the Route by default. During import, there is a method to retrieve an object based on this id, it contains "Session" in it, can't remember, but I think I used it for Taxonomy.

Aug 16, 2011 at 9:08 PM
Edited Aug 16, 2011 at 11:12 PM

Ok, so ChapterPartDriver now looks like:

        protected override void Exporting(ChapterPart part, ExportContentContext context)
            context.Element(part.PartDefinition.Name).SetAttributeValue("Position", part.Record.Position);

            var book = _contentManager.Get(part.Record.Book.Id);            
            var identity = _contentManager.GetItemMetadata(book).Identity.ToString();
            context.Element(part.PartDefinition.Name).SetAttributeValue("BookId", identity);

        protected override void Importing(ChapterPart part, ImportContentContext context)
            part.Record.Position = Int32.Parse(context.Attribute(part.PartDefinition.Name, "Position"));

            var identity = context.Attribute(part.PartDefinition.Name, "BookId");
            var contentItem = context.GetItemFromSession(identity);
            if (contentItem == null)
                throw new OrchardException(T("Unknown book: {0}", identity));
            part.Record.Book = contentItem.Record;

And it mostly works. I have one problem now. If I export, clear out the rows in the DB for Contrib_Chapters_ChapterPartRecord and Contrib_Chapters_BookPartRecord, and then import my data, it works. The books and chapters are restored. However, if I try to import the data to a brand new installation, only the Books are imported and the chapters are not. 

I believe this is due to the fact that the Chatper data is stored in its own ContentType (for my Chpaters in a book called "FirstBook" are created with the content type "FirstBookChapter". It appears that when these types are not already defined, then in DataRecipeHandler doesn't import them when it it calls:

_orchardServices.ContentManager.Import(element, importContentSession);

I could use some more guidance here. Your last suggestion got me past my block. Got any more advice?

Aug 17, 2011 at 2:11 PM
Edited Aug 18, 2011 at 4:51 PM

Deleting this post because it was wrong.

Aug 18, 2011 at 4:53 PM

Last comment (I hope), when you export you must select the types "Book" and the custom type created for your chapters. You must also export both Data and Metadata. The metadata is needed to recreate the custom type on import.

Aug 18, 2011 at 5:19 PM

Really nice. Do you want to create a source code fork and let me push it to the main repository ? I will test it and release a new version of the module then.

Aug 18, 2011 at 9:46 PM

I'll try. If I don't have time, can I just send you the two files I changed? All it was was adding the Importing and Exporting methods to BookPartDriver and ChapterPartDriver. It was very simple once I realized that a Part contains its own PartRecord as a field and that you have to export metadata in order to successfully reimport. 

Aug 18, 2011 at 9:46 PM


Aug 19, 2011 at 4:21 PM

Ok, I created the fork, installed TortoiseHg, made the changes to my local copy, committed to my local copy, and then I try to push the change to my fork. I'm getting an authorization failed error with error code 255.

[command returned code 255 Fri Aug 19 12:15:36 2011]
% hg --repository C:\devHg\Orchard.Source\src\Orchard.Web\Modules\Contrib.Chapters outgoing --quiet --template {node}^M
[command completed successfully Fri Aug 19 12:16:03 2011]
% hg --repository C:\devHg\Orchard.Source\src\Orchard.Web\Modules\Contrib.Chapters push
pushing to
searching for changes
http authorization required
abort: authorization failed
[command returned code 255 Fri Aug 19 12:16:39 2011]

In this thread the user had a similar problem and it was security configuration on the server. Can you check please? FYI, my fork is

Aug 19, 2011 at 4:24 PM

Weird :/

"Can you check please" check what, the server ????


Aug 19, 2011 at 4:29 PM

I don't know what to check. I assumed there were some types of project permissions settings on the core project. Perhaps there is some permission for "allow write to fork" or something that I need to be granted or Everyone needs to be granted.

Aug 19, 2011 at 4:35 PM

Ok, i took a shot and posted my question to said he fixed the problem. Now my push worked.