How to use Built in Fields for custom Module

Topics: Core
Jun 26, 2012 at 7:55 PM
Edited Jun 26, 2012 at 7:55 PM

What I want to do is create a module with say mediapickerfield and numericfield but i dont want to recreate them i know i can do something like...

 ContentDefinitionManager.AlterPartDefinition("Product",             

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

but how do I set the Product Image to something a controller? 

I've looked at the controller for MediaPickerField stuck at how I would set the image to something I have on my system. doing this for a bunch of pages I have... So I loop through pages I created and want to set the image to something on my machine.

Developer
Jun 26, 2012 at 8:35 PM
Edited Jun 26, 2012 at 8:36 PM

I think that's a two-step process: firstly, per image you loop through it should be copied to some folder under the Media folder of yor Orchard installation. While doing that, you can determine what relative url the image will have (using the site settings' root url appended with "Media" and the name of your tenant, which is "Default" by default. There's probably code you can either reuse or copy from the MediaPicker module).

The second step should be easy: since you're looping through your pages, all you woud have to do is cast that page to a variable statically typed to dynamic  (e.g. var p = (dynamic)currentPage) and access your field: p.Product.ProductImage.Url = relativePathOfTheImage.

And that should be it.

Jun 27, 2012 at 2:47 PM
Edited Jun 27, 2012 at 2:47 PM

The first step i know i have right done its the second step were you lost me lol. Sorry but maybe do you know any Modules in the gallery that do something similar to what im trying to do? Thank for the responses.

Developer
Jun 27, 2012 at 5:54 PM
Edited Jun 27, 2012 at 5:55 PM

Not from the top of my head, sorry. Although accessing a content field of a content item is done almost everywhere (although I can't seem to find a quick example for you. Anyone?)

It really is simply something like this:

foreach(dynamic page in myPages) {

   page.ProductPart.ProductImage.Url = "~/myimage.jpg";

}

This works as follows:

1. myPages is assumed to be a collection of ContentItems or ContentParts (the pages that you mentioned you'll be iterating over)
2. Because each iteration variable (page) is cast to dynamic, the attached Clay behaviors kick in when we access members of the variable.
3. I'm assuming that your page content type has a ProductPart attached. So when you invoke a member with the name ProductPart on a dynamic variable with the right Clay behaviors (which content items / content parts have), these behaviors will try and see if your content item has a part attached called "ProductPart".
4. Then, when we access a member called ProductImage on ProductPart, the Clay behaviors will go ahead and see if there is a field attached to that content part.
5. Finally, we can access the url of the ProductImageField (since it's of type MediaPickerField, even if it's typed as dynamic in the iteration: if no Clay behavior could handle the member accessing code, some default .NET behavior kicks in and checks if the object actually has a Url property, which it has )

Using dynamic is a great way to access a fields of parts of content items, because otherwise you would have to write code like this:

// Get the ProductPart
var productPart = (ProductPart)page.Parts.Single(p => p.Name == "ProductPart");

// Now get the ProductImage field
var productImageField = (MediaPickerField)productPart.Fields.Single(f => f.Name == "ProductImage");

// Now set the Url property to the image filename
productImageField.Url = "mypicture.jpg";

Or did you mean something else?

Jun 28, 2012 at 3:30 AM
Edited Jun 28, 2012 at 3:35 AM

Again thanks for the quick responses dude so just giving you some of my code that i know works i tried what you said nothing change in my output.. field remained empty.

This is what my controller looks like...

 foreach (newsItem news in brafton.News)
            {
                // if article doesn't already exist (checks for the article id in the route path)
                string check_slug = "News/Article/" + news.id + "/" + Slugify(news.headline);

                if (_contentManager.Query<AutoroutePart, AutoroutePartRecord>(VersionOptions.AllVersions)
                    .Where(rtpart => rtpart.DisplayAlias == check_slug).Count() <= 0)
                {
                    ContentItem article = _contentManager.New("Article");
                    article.As<TitlePart>().Title = news.headline;
                    article.As<AutoroutePart>().DisplayAlias = "News/Article/" + news.id + "/" + Slugify(news.headline);
                    article.As<BodyPart>().Text = news.text;
                    article.As<CommonPart>().CreatedUtc = news.createdDate;
                    article.As<ArticlePart>().ArticleID = news.id;
                    article.As<SiteCatalystPart>().PageName = "Article:" + news.headline;
                    article.As<SiteCatalystPart>().PageType = "Article";
                    // set article images
                    if (news.photos != null)
                    {
                        foreach (photo photoContainer in news.photos)
                        {
                            foreach (photo.Instance img in photoContainer.Instances)
                            {
                                // delimit to grab image name
                                int slashIndex = img.url.LastIndexOf("/") + 1;
                                string imageName = img.url.Substring(slashIndex, img.url.Length - slashIndex);
                                // create new url for image
                                string localImageURL = imageURL.Replace("{articleID}", news.id.ToString())
                                                               .Replace("{imageName}", imageName);

                                // call image scraper to save Brafton's image locally
                                ScrapeImage(img.url, localImageURL);

                                switch (img.type.ToString())
                                {
                                    case "Medium":
                                        article.As<ArticlePart>().PrimaryImage = localImageURL.Replace("\\", "/");
                                        break;

                                    case "Small":
                                        article.As<ArticlePart>().ThumbImage = localImageURL.Replace("\\", "/");
                                        break;
                                };
                            }
                        }
                    }           
                    _contentManager.Create(article, VersionOptions.Published);
                    _contentManager.Flush();

 

In the migration Content Type Aritlce(same as a page) has...

ContentDefinitionManager.AlterPartDefinition("ProductPart",             

builder => builder.WithField("ProductImage", fieldBuilder => fieldBuilder.OfType("MediaPickerField").WithDisplayName("ProductImage"))); 
Developer
Jun 28, 2012 at 1:24 PM

No problem man. I think that this is the issue:

article.As<ArticlePart>().PrimaryImage = localImageURL.Replace

 

What you're doing here is assigning localimageUrl.Replace to the PrimayImage field.
However (assuming that Replace is the actual url or path to the image), PrimayImage is of type MediaPickerField, so you cannot assign a string to a property of that type. Instead, you need to set the Url property of the media picker field:

article.As<ArticlePart>().PrimaryImage.Url = localImageURL.Replace

The same goes for the ThumbImage field.

 

Jun 28, 2012 at 2:40 PM

Sadly this didn't work for me said that string doesn't have Url method. Since in the migration we called it inside a string right?  What about the Media Service I was looking at it and was able to do something similar awhile back with the Taxonomies.

 public TaxonomyPart updateArticleTaxonomy()
        {
            TaxonomyPart articleTaxo = new TaxonomyPart();
            int pipe_index = 0;
            string parent = "";
            string child = "";

            // check to see if our ArticleTaxonomy already exists
            articleTaxo = _taxo.GetTaxonomyByName("ArticleTaxonomy");

            // if not, build it before importing articles
            if (articleTaxo == null)
            {
                articleTaxo = _contentManager.New<TaxonomyPart>("Taxonomy");
                articleTaxo.Name = "ArticleTaxonomy";
                articleTaxo.Slug = "News-Category";

                _taxo.CreateTermContentType(articleTaxo);
                _contentManager.Create(articleTaxo);
                if (_contentManager != null) {
                    _contentManager.Flush();
                }
            }

Now in the IMediaService what about something like...

string UploadMediaFile(string folderPath, HttpPostedFileBase postedFile, bool extractZip);

Jun 28, 2012 at 2:42 PM

I'm assuming MediaPicker is built off of Orchard.Media correct?

Developer
Jun 28, 2012 at 3:09 PM
Edited Jun 29, 2012 at 9:23 PM

You're right, my bad. I assumed they were content fields, but I they're properties of the ArticlePart.
But now I'm confused: you are defining a "ProductImage" field on a part called "ProductPart". Yet, I don't see a single line where you actually reference the "ProductImage" field. So it kinda makes sense that its value doesn't get set, right? Or I must be misunderstanding your issue.

Jun 28, 2012 at 3:37 PM

Sorry will explain, what I want is convert PrimaryImage and ThumbImage to built in Fields of MediaPicker Type. I made ProductPart included in my content type of "Article" ... here completely what my migration looks like.

using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
using Orchard.ContentManagement.MetaData;

namespace Northern.News
{
    public class Migrations : DataMigrationImpl
    {
        public int Create()
        {
            ContentDefinitionManager.AlterTypeDefinition("Article", builder =>
                builder.WithPart("CommonPart", p => p.WithSetting("DateEditorSettings.ShowDateEditor", "true"))
                .WithPart("TitlePart")
                .WithPart("AutoroutePart"));
            return 1;
        }

        public int UpdateFrom1()
        {
            ContentDefinitionManager.AlterTypeDefinition("Article", builder =>
                builder.WithPart("BodyPart")
                .Creatable()
                .Draftable());
            return 2;
        }

        public int UpdateFrom2()
        {
            ContentDefinitionManager.AlterTypeDefinition("Article", builder =>
                builder
                    .WithPart("BodyPart", partBuilder =>
                        partBuilder.WithSetting("BodyTypePartSettings.Flavor", "text")));
            return 3;
        }

        public int UpdateFrom3()
        {
            SchemaBuilder.CreateTable("ArticlePartRecord", table =>
                table.ContentPartRecord()
                    .Column<string>("PrimaryImage")
                    .Column<string>("ThumbImage")
                    .Column<int>("ArticleID")
                    .Column<bool>("IsFeatured"));

            ContentDefinitionManager.AlterTypeDefinition("Article", builder =>
                builder.WithPart("ArticlePart"));
            return 4;
        }

        public int UpdateFrom4()
        {
            ContentDefinitionManager.AlterPartDefinition("ArticlePart", builder =>
                builder.WithField("ArticleTaxonomy", fld =>
                    fld.OfType("TaxonomyField")
                    .WithSetting("DisplayName", "ArticleTaxonomy")
                    .WithSetting("TaxonomyFieldSettings.Taxonomy", "ArticleTaxonomy")
                    .WithSetting("TaxonomyFieldSettings.LeavesOnly", "False")
                    .WithSetting("TaxonomyFieldSettings.SingleChoice", "False")
                    .WithSetting("TaxonomyFieldSettings.Hint", "Select as many Categories as apply to this Article.")));


            SchemaBuilder.CreateTable("FeaturedArticlesPartRecord",
                table => table
                    .ContentPartRecord()
                    .Column<int>("Count")
                );
            ContentDefinitionManager.AlterTypeDefinition("FeaturedArticles",
                cfg => cfg
                    .WithPart("FeaturedArticlesPart")
                    .WithPart("CommonPart")
                    .WithPart("WidgetPart")
                    .WithSetting("Stereotype", "Widget")
                );
            return 5;
        }

        public int UpdateFrom5()
        {
            SchemaBuilder.CreateTable("RecentArticlesPartRecord",
                table => table
                    .ContentPartRecord()
                    .Column<int>("Count")
                );
            ContentDefinitionManager.AlterTypeDefinition("RecentArticles",
                cfg => cfg
                    .WithPart("RecentArticlesPart")
                    .WithPart("CommonPart")
                    .WithPart("WidgetPart")
                    .WithSetting("Stereotype", "Widget")
                );

            SchemaBuilder.CreateTable("ArticlePartArchiveRecord",
                table => table
                    .Column<int>("Id", column => column.PrimaryKey().Identity())
                    .Column<int>("Year")
                    .Column<int>("Month")
                    .Column<int>("PostCount")
                    );

            ContentDefinitionManager.AlterTypeDefinition("ArticlesArchive",
                cfg => cfg
                    .WithPart("ArticlesArchivePart")
                    .WithPart("CommonPart")
                    .WithPart("WidgetPart")
                    .WithSetting("Stereotype", "Widget"));
            return 6;
        }

        public int UpdateFrom6()
        {
            SchemaBuilder.CreateTable("ArticlesArchivePartRecord",
                table => table
                    .ContentPartRecord()
                );

            ContentDefinitionManager.AlterTypeDefinition("Article", builder =>
                builder.WithPart("SiteCatalystPart"));

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

            ContentDefinitionManager.AlterTypeDefinition("Article", builder =>
                builder.WithPart("ProductPart"));
            return 7;
        }
    }
}

So when I take a content item of "Article" i have included in Product Part.

I did try something like article.As<ProductPart>().ProductImage = localImageURL.Replace("\\", "/");

not luck :( no matter what you need a Model already created with that field inside it. Like with ArticlePart inside that model there is PrimaryImage and ThumbImage.

So I thought i could do something like ProductPart inside my model folder and inherit MediaFile Model from Orchard Media. MediaPicker does not have any Models just uses Media's.

Developer
Jun 29, 2012 at 9:31 PM

So in essence you want to set the value of a field to some value. In this specific case, you're looking to set the Url property of the MediaPickerField called "ProductImage". If correct, then it's exactly as I tried to explain earlier: cast the "article" variable to dynamic and assign the value to the field:

((dynamic)article).ProductPart.ProductImage.Url = localImageURL.Replace("\\", "/");

 

 

Jul 3, 2012 at 1:51 PM

Sorry didn't work setup just like that but the url didn't change. No error though just nothing happened when i went through me loop.

What other properties are under ProductImage? and how would I be able to find that Field's properties since it is dynamic. Thanks for the help.