Projection Query Filter using Tokens

Topics: Customizing Orchard, General, Troubleshooting, Writing modules
Apr 16, 2012 at 12:47 PM
Edited Apr 16, 2012 at 12:48 PM

Hi,

I want to have a widget that displays content that is context sensitive to the current item being displayed.

Using a Projection to do this, I am trying to create a query that has a filter that uses the Content.Id token.  However the filter always fails at line 81 in ContentTokens

77           if (context.Target == "Content") {
78                var forContent = context.For<IContent>("Content");
79                // is there a content available in the context ?
80                if (forContent != null) {
81                    foreach (var typePart in forContent.Data.ContentItem.TypeDefinition.Parts) {
82                        var part = typePart;
83                        foreach (var partField in typePart.PartDefinition.Fields) {
84                            var field = partField;
85                            var tokenName = "Fields." + typePart.PartDefinition.Name + "." + partField.Name;
86                            forContent.Token(
87                                tokenName,
88                                content => LookupField(content, part.PartDefinition.Name, field.Name).Storage.Get<string>());
89                            forContent.Chain(
90                                tokenName,
91                                partField.FieldDefinition.Name,
92                                content => LookupField(content, part.PartDefinition.Name, field.Name));
93                        }
94                    }
95                }
96            }

It seems as though the content item is not available when building the query.  I also found this issue http://orchard.codeplex.com/workitem/18498 which has been fixed in 1.4.1 (that I am using) that seems to point to this being the case!

Is there a way this can be achieved?

Thanks 

Developer
Apr 17, 2012 at 3:45 AM

Could you explain a bit more what kind of error are you running into (and paste a stack trace)? Null reference exception?

Been working with tokens recently and noticed that the check as it is in line 80 was actually always true. forContent.Data will be null when actual token data is not found, but not the forContent one. Looks like a bug, although I'm not sure if it's the source of your problem.

Apr 17, 2012 at 4:37 AM

You can't use Content-sensitive tokens in a filter because tokens require the content item to be available to produce values and you don't have content items, as I pointed out in that issue. You don't need to use the content id token anyway, I'm pretty sure you can use a built in filter or property bindings to get it.

I ran into that issue while I was building a module that does what I think you want to do. It requires 1.4.1 to work so I haven't published it.

It contains a field that allows you to reference content items from other content items. The selection is controlled via a query (So you can make a query for All Pages By Current Author for instance and those pages would be selectable via the field). It also supplies a Current Context token that is populated by whatever the current item is you are viewing, that works exactly like {Content}.

So using this module you can create a relationship via the Content Reference field, then in a widget or anywhere else, create a filter that says something like Content Reference Property Value Is Equal To {Context.Current.Id} to get all items that reference the current item. You could also do something like, get all items newer than the current item's creation date.

It also has a token provider that will load the referenced content, so you can rewrite field output as if you are joining.

Apr 17, 2012 at 7:02 AM
Yeah a Null Ref exception (sorry I'm not at my machine at the moment) and I think you are correct that forContent.Data should be checked for null.

On 17 Apr 2012, at 03:45, "pszmyd" <notifications@codeplex.com> wrote:

From: pszmyd

Could you explain a bit more what kind of error are you running into (and paste a stack trace)? Null reference exception?

Been working with tokens recently and noticed that the check as it is in line 80 was actually always true. forContent.Data will be null when actual token data is not found, but not the forContent one. Looks like a bug, although I'm not sure if it's the source of your problem.

Apr 17, 2012 at 7:04 AM
This sounds really interesting, any chance you can share the module? I am currently using 1.4.1.

Thanks for your help

On 17 Apr 2012, at 04:37, "CPyle" <notifications@codeplex.com> wrote:

From: CPyle

You can't use Content-sensitive tokens in a filter because tokens require the content item to be available to produce values and you don't have content items, as I pointed out in that issue. You don't need to use the content id token anyway, I'm pretty sure you can use a built in filter or property bindings to get it.

I ran into that issue while I was building a module that does what I think you want to do. It requires 1.4.1 to work so I haven't published it.

It contains a field that allows you to reference content items from other content items. The selection is controlled via a query (So you can make a query for All Pages By Current Author for instance and those pages would be selectable via the field). It also supplies a Current Context token that is populated by whatever the current item is you are viewing, that works exactly like {Content}.

So using this module you can create a relationship via the Content Reference field, then in a widget or anywhere else, create a filter that says something like Content Reference Property Value Is Equal To {Context.Current.Id} to get all items that reference the current item. You could also do something like, get all items newer than the current item's creation date.

It also has a token provider that will load the referenced content, so you can rewrite field output as if you are joining.

Apr 18, 2012 at 8:54 AM

I have a repository for it available at https://github.com/webadvanced/Orchard-ContentReference

No simple way to just download it at the moment, but I can push a tag up soon.

Apr 19, 2012 at 11:05 PM

Nice one, using your {Context.This.Id} has helped me solve my problem.

I can see that you load the current content item context via the OnActionExecuting using the IWorkContextAccessor.  Learnt something, thanks :)

In my situation I have a 1-n relationship, a course, with many testimonials. When the course page is loaded I want to show a random related testimonial.  The testimonial has a CoursePartRecord property to the related course.  To solve this I have created a custom query filter that requires a related course Id (using a tokenized field) that is used to build up the filter against the CoursePartRecord property.  Perhaps there is a way to do this without a custom filter?  I have tried but as the relationship is setup via the CoursePart and not the record, I don't seem to be able to expose it via a binding.

Thanks again for your help

Jul 5, 2012 at 9:45 AM

Hi CPyle, Thank you for making the module available. I downloaded and enabled but the reference field is not available as a custom field in content types. I'm, running Orchard 1.4.2, is there something I'm doing wrong, Thanks

Jul 5, 2012 at 7:16 PM

Go to your modules, and look for the Fields section. There should be one for "Content Reference Field." It depends on having Projector and Tokens enabled. If it's enabled, then I don't know what would be causing it to not show up as an option when adding a field. It does work in my Orchard 1.4.2 sandbox.

Jul 6, 2012 at 1:44 PM

Thanks for replying Cpyle, The field is enabled in the modules section but does not appear in drop down list on custom field types. Should the name "Content Reference" be appearing in the custom fields dropdown list or should I be using one of the existing fields that now has "content reference" functionality eg "Enumeration Field"?, thanks David

Jul 6, 2012 at 10:19 PM

It should appear in the list as its own field type., and if it isn't, then I don't really know what to say. It was originally made as a proof of concept to illustrate the power of the Projections module, and it isn't thoroughly tested.

I don't really support using the module yet anyway as it's not on the gallery, and it's complexity requires a bit of documentation to really make use of. Once (if) I publish it, I'll support it and take bug reports.

Jul 6, 2012 at 10:27 PM

Thanks CPyle, I would be one of many grateful developers if you do create this module. I really think this should be a core functionality, so i hopefully you do publish it. Thanks David