Adding ImageField to BlogPost in recipe?

Topics: Customizing Orchard
Jan 1, 2012 at 10:38 PM

Okay this is driving me nuts.  In my recipe I'm enabling the Contrib.ImageField module then attempting to add a custom field called "Thumbnail" to the BlogPost Content Type.

First, if I just do nothing but enable the module and then use the UI to add the new field, everything works brilliantly but I want to have this done immediately so I can actually add in BlogPost with images during setup.  

I used the export module and it exported this:

      <BlogPost ContentPartSettings.Attachable="True">        <Thumbnail.ImageField />      </BlogPost>

 

in the parts section.  In fact, this is all my <Parts> area contains:

    <Parts>

      <BlogPostPart />

      <BodyPart BodyPartSettings.FlavorDefault="html" />

      <BlogPost ContentPartSettings.Attachable="True">

        <Thumbnail.ImageField />

      </BlogPost>

    </Parts>

When this is added a few things get messed up.  For one, the ImageField isn't there.  Second, I can't even add a text/html or image field to the BlogPost.  Funny thing, the imagefield or any other field works so clearly the xml above really messes up BlogPost content type.

Perhaps I shouldn't be just blindly trusting the export module to help me structure the recipe XML but does anyone have any ideas?

Coordinator
Jan 2, 2012 at 9:25 PM

What version are you using? A bug with fields was fixed a couple of days ago on the 1.x branch.

Jan 2, 2012 at 9:28 PM

1.3.10 source download from about 2 weeks ago.

Question, how stable is the live 1.x code?

--------
John
Sent from a mobile phone

On Jan 2, 2012 3:25 PM, "bertrandleroy" <notifications@codeplex.com> wrote:

From: bertrandleroy

What version are you using? A bug with fields was fixed a couple of days ago on the 1.x branch.

Read the full discussion online.

To add a post to this discussion, reply to this email (orchard@discussions.codeplex.com)

To start a new discussion for this project, email orchard@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

Coordinator
Jan 2, 2012 at 9:31 PM

If you;re not already on 1.x you should probably stay clear of it. One thing you might want to do is download it anyways as a separate site, just to test if this still reproduces on the latest bits.

Jan 3, 2012 at 2:20 AM
bertrandleroy wrote:

If you;re not already on 1.x you should probably stay clear of it. One thing you might want to do is download it anyways as a separate site, just to test if this still reproduces on the latest bits.

I reviewed the change and the code set is quite a bit different.

Here is the file and differences from the item you mentioned:

http://orchard.codeplex.com/SourceControl/changeset/changes/752580332da0#src%2fOrchard%2fContentManagement%2fDrivers%2fContentFieldDriver.cs

Below is my file...any smoking guns that I'm not able to see?

using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Shapes;

namespace Orchard.ContentManagement.Drivers {
    public abstract class ContentFieldDriver<TField> : IContentFieldDriver where TField : ContentField, new() {
        protected virtual string Prefix { get { return ""; } }
        protected virtual string Zone { get { return "Content"; } }

        void IContentFieldDriver.GetContentItemMetadata(GetContentItemMetadataContext context) {            
            Process(context.ContentItem, (part, field) => GetContentItemMetadata(part, field, context.Metadata));
        }

        DriverResult IContentFieldDriver.BuildDisplayShape(BuildDisplayContext context) {
            return Process(context.ContentItem, (part, field) => Display(part, field, context.DisplayType, context.New));
        }

        DriverResult IContentFieldDriver.BuildEditorShape(BuildEditorContext context) {
            return Process(context.ContentItem, (part, field) => Editor(part, field, context.New));
        }

        DriverResult IContentFieldDriver.UpdateEditorShape(UpdateEditorContext context) {
            return Process(context.ContentItem, (part, field) => Editor(part, field, context.Updater, context.New));
        }

        void IContentFieldDriver.Importing(ImportContentContext context) {
            Process(context.ContentItem, (part, field) => Importing(part, field, context));
        }

        void IContentFieldDriver.Imported(ImportContentContext context) {
            Process(context.ContentItem, (part, field) => Imported(part, field, context));
        }

        void IContentFieldDriver.Exporting(ExportContentContext context) {
            Process(context.ContentItem, (part, field) => Exporting(part, field, context));
        }

        void IContentFieldDriver.Exported(ExportContentContext context) {
            Process(context.ContentItem, (part, field) => Exported(part, field, context));
        }

        void Process(ContentItem item, Action<ContentPart, TField> effort) {
            var occurences = item.Parts.SelectMany(part => part.Fields.OfType<TField>().Select(field => new { part, field }));
            foreach (var occurence in occurences) {
                effort(occurence.part, occurence.field);
            }
        }

        DriverResult Process(ContentItem item, Func<ContentPart, TField, DriverResult> effort) {
            var results = item.Parts
                    .SelectMany(part => part.Fields.OfType<TField>().Select(field => new { part, field }))
                    .Select(pf => effort(pf.part, pf.field));
            return Combined(results.ToArray());
        }

        public IEnumerable<ContentFieldInfo> GetFieldInfo() {
            var contentFieldInfo = new[] {
                new ContentFieldInfo {
                    FieldTypeName = typeof (TField).Name,
                    Factory = (partFieldDefinition, storage) => new TField {
                        PartFieldDefinition = partFieldDefinition,
                        Storage = storage,
                    }
                }
            };

            return contentFieldInfo;
        }

        protected virtual void GetContentItemMetadata(ContentPart part, TField field, ContentItemMetadata metadata) { return; }

        protected virtual DriverResult Display(ContentPart part, TField field, string displayType, dynamic shapeHelper) { return null; }
        protected virtual DriverResult Editor(ContentPart part, TField field, dynamic shapeHelper) { return null; }
        protected virtual DriverResult Editor(ContentPart part, TField field, IUpdateModel updater, dynamic shapeHelper) { return null; }
        
        protected virtual void Importing(ContentPart part, TField field, ImportContentContext context) { }
        protected virtual void Imported(ContentPart part, TField field, ImportContentContext context) { }
        protected virtual void Exporting(ContentPart part, TField field, ExportContentContext context) { }
        protected virtual void Exported(ContentPart part, TField field, ExportContentContext context) { }

        public ContentShapeResult ContentShape(string shapeType, Func<dynamic> factory) {
            return ContentShapeImplementation(shapeType, null, ctx => factory());
        }

        public ContentShapeResult ContentShape(string shapeType, string differentiator, Func<dynamic> factory) {
            return ContentShapeImplementation(shapeType, differentiator, ctx => factory());
        }

        public ContentShapeResult ContentShape(string shapeType, Func<dynamic, dynamic> factory) {
            return ContentShapeImplementation(shapeType, null, ctx => factory(CreateShape(ctx, shapeType)));
        }

        public ContentShapeResult ContentShape(string shapeType, string differentiator, Func<dynamic, dynamic> factory) {
            return ContentShapeImplementation(shapeType, differentiator, ctx => factory(CreateShape(ctx, shapeType)));
        }

        private ContentShapeResult ContentShapeImplementation(string shapeType, string differentiator, Func<BuildShapeContext, object> shapeBuilder) {
            return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx), differentiator)).Differentiator(differentiator);
        }

        private static object AddAlternates(dynamic shape, string differentiator) {
            // automatically add shape alternates for shapes added by fields
            // for fields on dynamic parts the part name is the same as the content type name

            ShapeMetadata metadata = shape.Metadata;
            ContentPart part = shape.ContentPart;
            var shapeType = metadata.Type;
            var fieldName = differentiator ?? String.Empty;
            var partName = part != null ? part.PartDefinition.Name : String.Empty;
            var contentType = part != null ? part.ContentItem.ContentType : String.Empty;
            var dynamicType = string.Equals(partName, contentType, StringComparison.Ordinal);

            // [ShapeType__FieldName] e.g. Fields/Common.Text-Teaser
            if ( !string.IsNullOrEmpty(fieldName) )
                metadata.Alternates.Add(shapeType + "__" + fieldName);

            // [ShapeType__PartName] e.g. Fields/Common.Text-TeaserPart
            if ( !string.IsNullOrEmpty(partName) ) {
                metadata.Alternates.Add(shapeType + "__" + partName);
            }

            // [ShapeType]__[ContentType]__[PartName] e.g. Fields/Common.Text-Blog-TeaserPart
            if ( !string.IsNullOrEmpty(partName) && !string.IsNullOrEmpty(contentType) && !dynamicType ) {
                metadata.Alternates.Add(shapeType + "__" + contentType + "__" + partName);
            }

            // [ShapeType]__[PartName]__[FieldName] e.g. Fields/Common.Text-TeaserPart-Teaser
            if ( !string.IsNullOrEmpty(partName) && !string.IsNullOrEmpty(fieldName) ) {
                metadata.Alternates.Add(shapeType + "__" + partName + "__" + fieldName);
            }

            // [ShapeType]__[ContentType]__[FieldName] e.g. Fields/Common.Text-Blog-Teaser
            if ( !string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(fieldName) ) {
                metadata.Alternates.Add(shapeType + "__" + contentType + "__" + fieldName);
            }

            // [ShapeType]__[ContentType]__[PartName]__[FieldName] e.g. Fields/Common.Text-Blog-TeaserPart-Teaser
            if ( !string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(partName) && !string.IsNullOrEmpty(fieldName) && !dynamicType ) {
                metadata.Alternates.Add(shapeType + "__" + contentType + "__" + partName );
            }
            
            return shape;
        }

        private static object CreateShape(BuildShapeContext context, string shapeType) {
            IShapeFactory shapeFactory = context.New;
            return shapeFactory.Create(shapeType);
        }

        [Obsolete]
        public ContentTemplateResult ContentFieldTemplate(object model) {
            return new ContentTemplateResult(model, null, Prefix).Location(Zone);
        }
        [Obsolete]
        public ContentTemplateResult ContentFieldTemplate(object model, string template) {
            return new ContentTemplateResult(model, template, Prefix).Location(Zone);
        }
        [Obsolete]
        public ContentTemplateResult ContentFieldTemplate(object model, string template, string prefix) {
            return new ContentTemplateResult(model, template, prefix).Location(Zone);
        }

        public CombinedResult Combined(params DriverResult[] results) {
            return new CombinedResult(results);
        }
    }
}
Coordinator
Jan 3, 2012 at 3:09 AM

windiff to the rescue I suppose.

Jan 3, 2012 at 3:12 AM
Thanks but if you compare the files you'll see they are quite different beyond the change he made. The version he modified appears to use a lot of newer .Net features than my copy from 1.3.10 so something dramatic changed the file before the minor change he made.

On Mon, Jan 2, 2012 at 9:09 PM, bertrandleroy <notifications@codeplex.com> wrote:

From: bertrandleroy

windiff to the rescue I suppose.

Read the full discussion online.

To add a post to this discussion, reply to this email (orchard@discussions.codeplex.com)

To start a new discussion for this project, email orchard@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com




--
================
John B Fraser
================

Coordinator
Jan 3, 2012 at 3:28 AM

Yeah, sorry, I don't have any other ideas right now. If I can, I prefer to do things in a migration rather than a recipe. For example, here is how I added a field to an existing type recently:

            ContentDefinitionManager.AlterPartDefinition("Product",
              builder => builder.WithField("ProductImage", fieldBuilder => fieldBuilder.OfType("MediaPickerField").WithDisplayName("Product Image")));

Jan 3, 2012 at 3:42 AM
Thanks, it's good to know I have options. I may try this as an alternative.

On Mon, Jan 2, 2012 at 9:28 PM, bertrandleroy <notifications@codeplex.com> wrote:

From: bertrandleroy

Yeah, sorry, I don't have any other ideas right now. If I can, I prefer to do things in a migration rather than a recipe. For example, here is how I added a field to an existing type recently:

            ContentDefinitionManager.AlterPartDefinition("Product",
              builder => builder.WithField("ProductImage", fieldBuilder => fieldBuilder.OfType("MediaPickerField").WithDisplayName("Product Image")));

Read the full discussion online.

To add a post to this discussion, reply to this email (orchard@discussions.codeplex.com)

To start a new discussion for this project, email orchard@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com




--
================
John B Fraser
================