I have following code (in grails and Searchable Plugin aka Compass):
class Topic {
String name;
static searchable = true;
}
class Question extends BaseEntity {
String question;
static searchable = true;
static hasMany = [
topics: Topic
]
}
How can I search Question with specific topic id?
Something like Question.search("topics#id:12") or Question.search("topics.id:12") dosnt work.
Chage your searchable block in Question so it looks like this:
static searchable = {
topics component: true
}
and in Topic if you dont want Topics returned as root search elements
static searchable = [
root: false
]
Fire up grails and add a few items, then download Luke from http://www.getopt.org/luke/
and open the index for your Question domain object which will be at ~/.grails/projects/projName/searchable-index/'env'/index/question
If you check the documents tab you will see the terms embedded in the index which will be something like $/Question/topics
This should give you the path to put in your Question.search, something like:
Question.search('$/Question/topics/id:1')
Related
Good day!
In my Orchard, I have several content types all with my custom part attached. This part defines to what users this content is available. For each logged user there is external service, which defines what content user can or cannot access. Now I need access restriction to apply everywhere where orchard display content lists, this includes results by specific tag from a tag cloud, or results listed from Taxonomy term. I seems can’t find any good way to do it except modifying TaxonomyServices code as well as TagCloud services, to join also my part and filter by it. Is this indeed the only way to do it or there are other solutions? I would like to avoid doing changes to built-in modules if possible but cannot find other way.
Thanks in advance.
I'm currently bumbling around with the same issue. One way I'm currently looking at is to hook into the content manager.
[OrchardSuppressDependency("Orchard.ContentManagement.DefaultContentManager")]
public class ModContentManager : DefaultContentManager, IContentManager
{
//private readonly Lazy<IShapeFactory> _shapeFactory;
private readonly IModAuthContext _modAuthContext;
public ModContentManager(IComponentContext context,
IRepository<ContentTypeRecord> contentTypeRepository,
IRepository<ContentItemRecord> contentItemRepository,
IRepository<ContentItemVersionRecord> contentItemVersionRepository,
IContentDefinitionManager contentDefinitionManager,
ICacheManager cacheManager,
Func<IContentManagerSession> contentManagerSession,
Lazy<IContentDisplay> contentDisplay,
Lazy<ISessionLocator> sessionLocator,
Lazy<IEnumerable<IContentHandler>> handlers,
Lazy<IEnumerable<IIdentityResolverSelector>> identityResolverSelectors,
Lazy<IEnumerable<ISqlStatementProvider>> sqlStatementProviders,
ShellSettings shellSettings,
ISignals signals,
//Lazy<IShapeFactory> shapeFactory,
IModAuthContext modAuthContext)
: base(context,
contentTypeRepository,
contentItemRepository,
contentItemVersionRepository,
contentDefinitionManager,
cacheManager,
contentManagerSession,
contentDisplay,
sessionLocator,
handlers,
identityResolverSelectors,
sqlStatementProviders,
shellSettings,
signals) {
//_shapeFactory = shapeFactory;
_modAuthContext = modAuthContext;
}
public new dynamic BuildDisplay(IContent content, string displayType = "", string groupId = "") {
// So you could do something like...
// var myPart = content.As<MyAuthoPart>();
// if(!myPart.IsUserAuthorized)...
// then display something else or display nothing (I think returning null works for this but
//don't quote me on that. Can always return a random empty shape)
// else return base.BuildDisplay(content, displayType, groupId);
// ever want to display a shape based on the name...
//dynamic shapes = _shapeFactory.Value;
}
}
}
Could also hook into the IAuthorizationServiceEventHandler, which is activated before in the main ItemController and do a check to see if you are rendering a projection or taxonomy list set a value to tell your content manager to perform checks else just let them through. Might help :)
I have extended the built-in User ContentType with a Content Picker Field that can be used to select multiple Video ContentItems. This gives me a video multi-picker control on the Edit page of each User.
I love how Orchard CMS makes this so elegantly simple to setup.
Now that I can associate multiple Videos with a User, I'd like to create a Query that will display just the Videos that the currently logged in User has been granted access.
I was hoping to be able to setup a Query using the Projector module, in what I thought was the obvious way (see below), but this returns no results.
This is how I configured the second filter:
Clicked on the + Add a new Filter link on the Edit Query screen
Chose Videos:Ids from the User Content Fields section, like this:
Configured the new filter like this:
What am I doing wrong, or what is the simplest way of diagnosing this issue?
This is how the Content Picker field is defined:
I have spotted my error - it was due to me not having a proper understand of how the filters worked. The Videos:Ids filter in the User Content Fields section does not give access to the current user's list of videos, as I assumed. Instead, it is offering the field to be used in the filter, which would be useful if I were to write a query to produce a list of Users that had access to a specific Video.
It was wishful thinking that it worked the way I wanted, but it's obvious in retrospect how it actually works.
Update: in the hope it's useful for others, here's the custom filter I developed:
public interface IFilterProvider : IEventHandler
{
void Describe(dynamic describe);
}
public class CurrentUserVideosFilter : IFilterProvider
{
private readonly IWorkContextAccessor _workContextAccessor;
public CurrentUserVideosFilter(IWorkContextAccessor workContextAccessor)
{
_workContextAccessor = workContextAccessor;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public void Describe(dynamic describe)
{
describe.For("My Filter Category", T("My Filter Category"), T("My Filter Category"))
.Element("Current User's Videos", T("Current User's Videos"), T("Current User's Videos"),
(Action<dynamic>)ApplyFilter,
(Func<dynamic, LocalizedString>)DisplayFilter,
null
);
}
public void ApplyFilter(dynamic context)
{
var query = (IHqlQuery)context.Query;
context.Query = query.ForType("Video")
.Where(x => x.ContentPartRecord<IdentityPartRecord>(), x => x.InG("Id", GetVideoIdsForCurrentUser()));
}
private IList<int> GetVideoIdsForCurrentUser()
{
var currentUser = _workContextAccessor.GetContext().CurrentUser;
if (currentUser == null) return new int[0];
dynamic item = currentUser.ContentItem;
var videoContentItems = (IEnumerable<ContentItem>)item.User.Videos.ContentItems;
return videoContentItems.Select(i => i.Id).ToList();
}
public LocalizedString DisplayFilter(dynamic context)
{
return T("Videos that have been assigned to the currently logged in user");
}
}
I created this class in a new Orchard module, which contains all my customisations for the site I'm building. Once I installed the module, the filter was immediately available. I assume Orchard uses reflection to seek out all types that implement the IFilterProvider interface.
This is how the filter appears on the Add a Filter screen:
Clicking on the filter shows this screen:
Once the filter has been saved, the query works exactly how I'd like - it shows all videos that have been assigned to the currently logged in user.
Using Grails (or hibernate), I was wanting to know if there is a specific design pattern or method we should be using when implementing a SEARCH of our domain.
For example, on my website, I want to be able to filter(or search) by multiple properties in the domain.
EG: For I have a page which displays a list of HOTELS. When I submit a search form, or if a user clicks "filter by name='blah'", when I enter the controller I get the following:
Domain
String name
String location
Controller
if(params.name && params.reference) {
// Find name/reference
} else if(params.name) {
// Find name
} else if(params.reference) {
// Find reference
} else {
// Find all
}
As you can understand, if there are more properties in the domain to search/filter, the longer the controller gets.
Any help. Please note, I do not want to use the 'searchable' plugin, as this is too complex for my needs.
I would embed these in a named query in the Domain class itself. For example:
Class Hotel {
String name
String city
String country
boolean isNice
static namedQueries = {
customSearch { p ->
if (p?.name) eq('name', p.name)
if (p?.city) eq('name', p.city)
if (p?.country) eq('name', p.country)
if (p?.isNice != null) eq('isNice', p.isNice)
}
}
}
Then later in a controller somewhere ...
def results = Hotel.customSearch(params)
Of course this is a very simple example, but you can expand on it using the same named query or even adding others and chaining them together.
I'm using play framework 1.2.7 to create a simple page to search some data on a database.
I already have one of the listing pages with CRUD module. The problem is that the search is a text field that searches in all text columns. I want to customize this.
The default is:
#{crud.search /}
I imagine I should be able to do something like:
#{crud.search }
... search fields...
#{/crud.search}
But I can't find any documentation about it.
How can I define the fields to search and how to use them?
What it worked for me was to overwrite the list method in the controller that extends from CRUD.
For example:
public static void list(int page, String search, String searchFields,
String orderBy, String order) {
ObjectType type = ObjectType.get(getControllerClass());
notFoundIfNull(type);
if (page < 1) {
page = 1;
}
List<YourObject> yourObjects;
List<Model> objects;
yourObjects = YourObject.yourSearch(search);
/* I also wanted to keep the standard search
so from here I also kept the standard code */
....
}
I;'m having a problem with the searchable plugin (0.6.4).
My domain classes that are involved in my problem are these ones:
class AdminArea {
static searchable = true
String name
static belongsTo = [country:Country]
}
and (I have deleted non important fields):
class POI{
static searchable = {
adminArea component: true
}
String name
AdminArea adminArea
}
What I have in my app is a normal searchbar and a select that lets me choose the admin area so I can narrow the results a bit. To accomplish this, I have been trying to do the following:
In my searchable Controller, where I build the query:
def results = POI.search({
must{
queryString(searchTerm)
must(term('adminArea', params.adminArea))
}
})
I have tried with many combinations, like adminArea.id, adminArea.name, changing the values of the select in the gsp to ids, names.... but nothing seems to do the trick, I cant notice what I am missing.
I have found a way through rhis.. the queries in searchable are not good at all, so I have to came around and solve it like this:
def results = POI.search{
must(queryString(searchTerm + " AND adminArea.id: " + params.adminArea))
}