Content Type/Part Integration

Topics: Customizing Orchard, Writing modules
Jun 16, 2012 at 7:36 AM

Hi,

I have just started out looking at Orchard, and this for very specific needs. For what I have read and understood about custom modules and content types/parts, multiple things need to be done to expose custom data to orchard, and I quote Skywalker Software here:

To recap, there are a couple of steps to follow to create a ContentPart that can persist information in the database:

  1. Create a Record class that represents your entity
  2. Create a ContentPart class that derives from ContentPart<TRecord>
  3. Create a Migration for your content part that defines the database schema
  4. Create a Driver for your content part
  5. Create an editor template for your content part
  6. Add a StorageFilter for your content part using a Handler

I am working with an Integration API that exposes both metadata and data from external systems. This metadata might change at any given point in time.  What I would like to achieve is to make some form of dynamic content type/part that can provide columns/fields of data to Orchard based on the metadata that is read from the Integration API.  Can anyone shed a light on whether this is actually possible, maybe by providing a custom interface to a storage/repository provider or something?  Thanks in advance...

Regards,

Andy

Developer
Jun 16, 2012 at 8:07 PM

Hi Andy,

You can dynamically weld content fields on to your custom content part. So your custom content part wouldn't have any class properties, just content fields welded on by you based on the metadata coming from the integration API.

Jun 16, 2012 at 8:33 PM

Thanks for your response :)

It's good to hear that there are options.  Are there some samples of how to do this, maybe in the source code of orchard or something?  Your help is much appreciated.

Btw, I'm a bit stuck with your tutorial on Orchard 1.4.2.  The Books Catalog item that is created in the admin area shows the edit form for the product catalog rather than the books list where books can be selected.  I had to change the Routepart with TitlePart and AutoroutePart, don't know if that has anything to do with it...

Thanks,

Andy

Developer
Jun 16, 2012 at 9:44 PM
Edited Jun 16, 2012 at 9:47 PM

Absolutely, almost every module uses the IContentDefinitionManager class to define content types, parts and in some cases fields. Look for Migrations.cs files in the root of each module to see how new parts are defined. Content Parts, -Fields and -Types are defined like so:

ContentDefinitionManager.AlterPartDefinition("DynamicPart",
                cfg => cfg
                    .WithField("FirstName", field => field.OfType("TextField").WithDisplayName("First name"))
                    .WithField("LastName", field => field.OfType("TextField").WithDisplayName("Last name"))
                    .WithField("Birthdate", field => field.OfType("DateTimeField").WithDisplayName("Birthdate"))
                );

            ContentDefinitionManager.AlterTypeDefinition("DynamicContent", type => type
                .WithPart("DynamicPart", part => part
                    .WithSetting("DateTimeFieldSettings.Display", "DateOnly")
                )
            );

If the DynamicPart doesn't yet exist, it is created. Otherwise all operations you perform will modify the part, such as adding fields and changing properties.
Because a part is useless by itself, you need to attach it to a content type. When defining the content type, you attach the DynamicPart and any other part that suits your needs. It's almost as if playing with lego pieces (be it rather advanced pieces).

It's at the content type / part level where you configure the field settings (as I did in the example with the DynamicContent type). If you're unsure what settings exist, just configure your parts and types using the admin and then export the type. The exported XML will show you the names of the settings. Alternatively, you can search for setting classes in the Settings folder of a module. The name of a setting is built using the name of the class (e.g. "DateTimeFieldSettings") and then the property name (e.g. "Display").

Although most modules only use the IContentDefinitionManager in the Migrations class, you're free to use it whenever you like. For example, if you have a controller, just inject a IContentDefinitionManager via the constructor and store it in a class level variable (a field or property) and manipulate your content part and types as you see fit.

As for the tutorial, it's not yet up to date for 1.4. You did quite right to replace the RoutePart with the TitlePart and AutoroutePart. If you do that everywhere, I believe you'll fix most of the incompatiblity issues. As a nice additional excercise, you may want to replace the ProductCatalog (which is a List) with a Projection. That will even allow you to display a list of products of any product type (not just books).

Jun 16, 2012 at 9:56 PM

Thanks for the superb explanation :)

I will have a play with this, I definitely see some very nice possibilities here...

I will also have a look at projections; can these be created programmatically as well?