I think we initially talked about this, but somehow it got lost, or maybe we/you decided against it after all.
The thing is that there are several other modules, like Search API Saved Searches and Search API Autocomplete, which need a mechanism to find out about the different searches/search pages that exist for a given index (or in general). So I think it would be greatly benefitial for these modules to move some of this search page discovery mechanism from Facets into the Search API.
My plan here would be to have a "Search page" (or a better name, if someone comes up with one) plugin in the Search API, with a few search-specific methods like getIndex()
, getPath()
, getSearchId()
, getResults()
(with the option to execute the search if the results aren't there (yet)) and even isRenderedInCurrentRequest()
.
An implementation with a deriver to produce plugins for every Views page would of course be in the Search API, and you'd just have to change the code to have only a single class for all Search API facet sources, using that Search API plugin, and having a deriver that creates one facet source for every search page.
The large advantage for everyone would be larger adoption, since this would then live directly in the Search API, and other modules would be even more inclined to implement the plugin for their search pages. (I'd also be thinking about a supportsFeature()
mechanism, like for backend plugins – that way, there would be a clear way of implementing support for things like Autocomplete, which needs specific search-specific support. However, it doesn't seem to me like your code actually needs that – just the generic information cited above, as far as I can see.)
Would you be willing to make such a change?
I think it would be quite easy, just the normal boilerplate code to write for a new plugin type, but other than that pretty clean. However, it would of course again be a disruption in compatibility, so it would be a change that should happen sooner rather than later.
(Also, completely unrelatedly, I think this project needs a few more issue queue "Components" – "Search API integration", "Core Search integration", and maybe others. Having not just the default four will surely be helpful in the long term, when the module and its usage grow.)
Comment | File | Size | Author |
---|---|---|---|
#50 | 2648260-50--display_plugin.patch | 18.67 KB | drunken monkey |
Comments
Comment #2
StryKaizerThis sounds great as search api sorts can also benefit from this.
We decided on not implementing seach api sorts, but since this part of the code is/was living in facets atm, it did make sense thinking about it.
+1 on moving the parts which make sense to search api.
Comment #3
Nick_vh+1 - same reasoning as StryKaizer. Would love to see that in Search API so other modules can benefit from that. However, we should be careful not to brake current mechanisms in Facet API so the easiest way to do this is to keep the facet source in Facet API but make generic functions in Search API that are then called by the Facet Source. This might not be that easy and potentially becomes very complex.
We could also move over the complete facet source so that Search API can do this refactoring without breaking Facet API all the time. As long as there is a facet source available, Facet API is happy. So I suppose this is a 2 step issue. Step 1: Move the Facet Source, Step 2: Break out the Facet Source to generic functions and classes so that other modules can also use those without breaking Facet API.
Comment #4
borisson_In moving over the plugin-type facetSource to search_api, we're going to be requiring modules that work with core search (core_search_facets) or views (core_views #2630896: Generic views support) to also rely on search_api.
I don't think this is a good idea to introduce that dependency.
So I think it's a -1 from me, unless I don't fully understand.
Comment #5
borisson_Adding a related issue.
Comment #6
drunken monkeyNo, you misunderstood there. We don't want to move the plugin type, we want a new plugin type in the Search API that does more or less the same – provide information for a single search "page" (or whatever) and allow configuration of that. The facet source plugin type would stay in the Facets module, but the Search API implementation for it would just be a single class, with derivatives for all of the Search API "search page" plugins, that redirect all page-specific methods to the corresponding "search page" plugin.
And yes, Nick, the move would of course need to be coordinated. However, I still don't think that we need to move the facets source plugin to the Search API, nor that we should – seems that would make it harder, in turn, to make changes to the facet source plugin type afterwards. Also, I think there was a problem with the interdependence of the facet source and widget plugins?
Comment #7
borisson_I know I understood, @Nick_vh and @StryKaizer explained why this is a good idea. I think we should do this. Do you think we can do this before this week's round of alpha releases?
Comment #8
StryKaizerMoving this to Search API, as the first action is in this module.
Comment #9
StryKaizerI used the name "Display" instead of Search Page, as Views uses "Display" for something which relates the most to what we are implementing here.
Feel free to discuss and/or change that name ;)
Also, do we need a search_api_display_info_alter hook for this? Cant think of a usecase yet for that hook though.
Comment #10
borisson_I like the display name, that has my vote. Overall this looks great, I found a couple of smaller things.
@drunken monkey: is there any way we can write tests for this?
Should be only one blank line.
Can we typehint on the interface instead of the class here?
I'm not sure if the interface should extend the
DerivativeInspectionInterface
. I think the base class should implement that interface instead./s/Retrieves/Returns/ for more consistency in the methods.
/s/Display/display/
This exceeds 80 cols.
Manages display plugins
I think this can be changed to {@inheritdoc}
Comment #11
drunken monkeyGreat job, thanks a lot! Looks quite good already.
Also, of course, thanks to Joris for the thorough review, as usual!
Sure. E.g., we could add a check to
ViewsTest
to see if the corresponding display plugin for the view is available and has the correct information (label, description, path).I disagree, we do the same for all the other plugin types as well. Doing it the other way, you'd need additional
instanceof
checks wherever you need to use such a method – and I don't think they're doing any harm just being there when they're not needed.Also, I spotted a few other minor issues with the patch:
In both files, I think we currently have alphabetic ordering, which we should preserve here.
I think the type hint isn't necessary (any more?) with PhpStorm and the Symfony plugin. Since that's the de-facto standard, I'd rather leave that out now.
I think there's
->entityTypeManager()
, too, instead of usingservice()
.Why isn't there a
getDescription()
method as well? (Btw, ugly that we uselabel()
instead ofgetLabel()
, but I guess we're stuck with that now.)Or, if we don't want descriptions for displays, they should be removed from the annotation.
Please use
array()
instead of[]
. Same in the rest of the code.It probably was the wrong decision back then, but I'd say the time to adapt the new style in this module is over now.
Is it really legal to have two colons in the plugin ID? It seems like this might cause issues in some cases. (Also see #2565045-6: Document valid plugin ID format.)
On the other hand, come to think of it, you might need to have those in the Facet API then as well, right? If you want derivatives for all Search API displays, but they might already be derivatives themselves.
Might need a clever solution there.
For here, though, maybe just use a double underscore or something like that instead?
How about just
'View %view, display %display'
instead for the label?Also, is there something better we can use for the description? At the very least, I'd change this to something like
'Represents the page display %display of view %view.'
(i.e., a more verbose version of the label). But I think views also have descriptions, so maybe use that (if available) and just add the display name at the end?But, as said, in general great work!
Comment #12
drunken monkeyChanging the title – the Facet API changes should then probably live in a new follow-up issue.
Comment #13
StryKaizerRemark 6 from #11 still needs to be addressed.
Comment #14
StryKaizerUsing patch in #13 for search_api sorts to use displays instead of index for configuration.
Should we add getDisplay() to the QueryInterface, so modules (e.g. search_api_sorts) can detect which display fired the query?
Or is there another way to do this?
Comment #15
borisson_Would it be enough to do
$plugin->getPluginDefinition()['view_display']
instead @StryKaizer?Comment #16
StryKaizer@borisson_ The reason why I need a way to identify the Display which fired the Query, is because "Search api sorts" needs to do the correct query alter using hook_search_api_query_alter.
At this moment I can only do alters based on the index, not specificly target the Display.
Comment #17
drunken monkeyThanks a lot for your continued work on this!
Wouldn't it be better to return a
Url
object here? Just having a path, without even the possibility of GET parameters, seems a bit restrictive.Displays don't seem to have a description at the moment.
You can't use
IndexPluginBase
here, as that's always configurable. You'll need to include the index handling manually.Also, I guess in the case of displays, the index isn't passed through the plugin configuration, but determined by the plugin itself?
For the default
getIndex()
implementation, maybe just check whether there is an'index'
key in the definition, instead? (Should then probably also be in the annotation/documentation.)Copy/paste error, it seems.
I think he means Search API display, not the Views display.
And yes, @StryKaizer, I guess that would make a lot of sense. The question is, how to set it? Just a setter, or as a special option?
With an option, we wouldn't really need the method, just let people access the option directly, instead. A bit worse DX-wise, but on the other hand we can't (or, at least, don't) add separate methods for all known options.
What would you say?
In any case, though, being able to determine which display triggered a search query is of course important and sensible functionality.
Comment #18
borisson_Attached patch fixes #17.1, .2 and .4. I haven't changed .3 yet.
Comment #19
drunken monkeyThanks, good work!
So only #11-6 and #17-3 need to be addressed now. (The former is pretty tricky, though. I've asked in #2565045-8: Document valid plugin ID format, maybe someone can help.)
Comment #20
drunken monkeyHow about this? The solution for #11-6 here is pretty simple – just use a double underscore instead of a colon. Since the view and display IDs are already in the plugin definition, we don't really need the plugin ID to be parseable.
The only downside is that this might, in rare situations, lead to conflicts (i.e., when two displays on two different views have the same combined machine name, which means that one view ID and one display ID (of the other view) would have to contain double underscores, too – and even that would only be a problem in very specific circumstances) – but I think the chance is minimal enough to live with it. Otherwise, unless we want to risk the potential issues with two colons in a plugin ID (and I'd guess that would be considerably riskier), we'd probably have to keep a table where we store the "sanitized" plugin IDs, to make sure we always create the plugin ID for a certain display.
In any case, I'd say you can use the exact same mechanism on the Facets side, too – just take our display plugin IDs, replace any plugin derivative seperators (i.e., colons) with double underscores, and you should be fine.
Comment #23
drunken monkeyThat one was on you, Joris! :P
Comment #24
borisson_I think this is looking great, but I'd love to get sign-off from @StryKaizer
Comment #25
borisson_I noticed that we're only supporting page displays for now. We recently started supporting blocks in facets as well - see http://cgit.drupalcode.org/facets/commit/?id=196a64e284b760e8d68b248fd67...
We can do that as a follow-up though.
I also found a couple of nitpicks that can be updated.
Comment #26
StryKaizerAdded the display to the query object using setOption
Comment #27
borisson_Now that @StryKaizer confirmed that this works sufficiently, I'd say this is RTBC.
Comment #28
StryKaizerLooks like isRenderedInCurrentRequest is not yet working.
Comment #29
StryKaizerAdded isRenderedInCurrentRequest for ViewsPageDisplay
Comment #30
borisson_Looks great, no complaints here.
Comment #31
StryKaizerAdded getDescription to the interface and baseclass.
Comment #32
StryKaizerComment #33
StryKaizerNot sure how I missed this. Now returning the correct Search api display plugin when using views (instead of the views display, which is irrelevant).
I also added a todo, since we should allow other modules to alter the views query to support new views display modes.
Anyone any idea how? A hook_search_api_views_displays_info() hook or any better ideas?
Comment #34
drunken monkeyThanks, great job!
Still, a few more changes (it also needed a re-roll). Please see if you're OK with them.
Also, as a suggestion, should we maybe also just include the base path in the plugin definition? Then, I think, the plugin base class could also have default implementations for those two methods (and
ViewsPageDisplay
would be empty – but nothing wrong with that, really).Comment #35
borisson_This doesn't look right
Comment #36
StryKaizerFixed current path check, so it works with language prefix too
Tried to inject the current path service with DI and failed miserably, so feel free to fix that.
Also removed double label from #35
Comment #37
borisson_Let's see how the bot feels.
Comment #38
borisson_I think I can change this back to RTBC. I'm really happy with the current patch and this patch is required to make search_api_sorts work. We can't release an alpha there, before there's another alpha release for search_api that includes this patch.
Comment #39
drunken monkeyThe second label was probably meant to become a description and I somehow lost track between duplicating the line and actually changing it.
Thanks, and did that (hopefully).
Please verify path detection still works correctly (since we don't have tests for that yet).
Comment #42
drunken monkeyViews …
Comment #45
drunken monkeyThen maybe like this?
Comment #46
borisson_:-)
This should be the FQDN
Same here.
Other changes look good.
Comment #47
drunken monkeyThanks for spotting that. So this should be RTBC?
You probably mean "FQN". ;)
Comment #48
borisson_I think this is rtbc, yeah. Not sure if we want to have @StryKaizer verify that this all works for search api sorts before committing this?
I did, yes.
Comment #49
StryKaizerShould be:
return $current_path == '/' . $plugin_definition['path'];
Comment #50
drunken monkeyOops, thanks a lot for catching that!
Then, if we always want to prepend a slash anyways, let's just prepend it right in the definition.
Comment #51
StryKaizerLooking good!
Setting rtbc
Comment #52
borisson_RTBC++
Comment #54
drunken monkeyExcellent. Committed.
Thanks again, everyone!