Closed (fixed)
Project:
Search API
Version:
8.x-1.x-dev
Component:
Drush / Rules
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
6 Oct 2017 at 17:31 UTC
Updated:
6 Jan 2018 at 16:09 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
drunken monkeyOK, thanks, good to know!
When will it be released? Is the class structure already fixed, and is there some documentation?
Comment #3
borisson_As far as I know it's pretty close a beta-6 release was already tagged. There's documentation on how to port the commands: https://weitzman.github.io/blog/port-to-drush9
Comment #4
kevin.dutra commentedComment #5
kevin.dutra commentedHere's a pretty 1:1 port. As a note for any future work, the table formatting is fairly picky; for instance, without the
@returnannotation in the method, it doesn't output correctly (missing table headers, columns not aligned, etc.).Comment #6
kevin.dutra commentedComment #7
claudiu.cristeaReviewing and fixing
Comment #8
claudiu.cristeaThe new patch contains next changes:
Usually we use the full qualified reference:
\Exceptionand avoiduse \Exception;.About naming:
search_api, sosearchandapiare not separate things becauseapiis not a subcommand ofsearch. The prefix of all commands should besearch-api:.search:api:reset:trackershould be
search-api:reset-trackerbecause "reset tracker"is the command, so the two words should be together, separated by dash. the same applies to
search:api:server:list,search:api:server:enable,search:api:server:disable,search:api:server:clear,search:api:set:index:serverFor the same reason mentioned before, we should remove the "api" prefix from the method names. Note that "list" is a reserved word for method name in PHP >= 7. So let's use listCommand().
We should replace the old canonical command name with the new one in
@usage.@throwsshould go to the end of docblock and needs explanation.s/private/protected
Comment #9
claudiu.cristeaSome commands were not aware if the param is optional or not.
Comment #10
pfrenssenAt first glance this looks great but dependencies are not injected properly. Assigning to me to do a thorough test and dependency inject all the things.
Comment #11
borisson_I'm also not sure if we want to add all of these things in one single class, adding a new 1k-line class doesn't sound like the best idea. Is there a way we can split this up into smaller components?
Perhaps splitting up like this:
On the other hand, I recently talked with @bircher about the way he was doing the drush/console commands in config split. He said that he has all of the commands in a service (http://cgit.drupalcode.org/config_split/tree/src/ConfigSplitCliService.php) and all of them have integration for drush 8 (http://cgit.drupalcode.org/config_split/tree/config_split.drush.inc), drush 9 (http://cgit.drupalcode.org/config_split/tree/src/Command) and drupal console (http://cgit.drupalcode.org/config_split/tree/src/Commands).
I would love to also go into that direction. Because right now we have duplication of all the code (which is not awesome). We also have 0% testcoverage for anything related to those commands, if the integration with drush/console is just a thin wrapper around a tested service that's not that big of a problem.
However, that is a very big refactor, I don't want to start on that without getting a thumbs up from thomas. I also think we can do that as a followup while keeping this one smaller and do just the addition of drush 9.
So maybe for now, we should just do #9 (or whatever @pfrenssen comes up with) and do this refactor later?
In any case, thanks @claudiu.cristea and @kevin.dutra for kicking this off. This is a great start!
I'll review the patch after @pfrenssen posts his version.
Comment #12
claudiu.cristeaI really don't see the point here, except, probably, code readability. We split, then we have 2 services.
EDIT: @pfrenssen, yes I wanted to add injection. Finally I forgot.
Comment #13
pfrenssenResults from manual test:
$ drush sapi-l --format=listThis outputs numbers instead of the machine names of the search indexes.
These work great, I also like that the commands are not returning any output, this is according to UNIX best practices.
$ drush sapi-sidorindexId. I would go forindex. The other commands are also having this issue.--format=listoption doesn't make sense for this command, since there will not be any status being output.drush sapi-landdrush sapi-s.$ drush sapi-iHelp texts are not correct, it mentions that we can do
$ drush sapi-i index 100 10while in reality it is$ drush sapi-i index --limit=100 --batch-size=10.$ drush sapi-rIs it really necessary to have this large amount of aliases?
$ drush sapi-cWorks great. I can't see any difference afterwards in
drush sapi-sthough after executing this ordrush sapi-r. Both report 0% indexed with 0 items, but they actually work as expected, the search index is empty after clearing but not after marking for reindexing.$ drush sapi-searchThis is awesome, but the "--format=list" option returns numbers instead of the search result IDs.
$ drush sapi-slSame problem, the "--format=list" option returns numbers instead of server IDs.
$ drush sapi-se$ drush sapi-sd$ drush sapi-sc--verboseoption is passed. Commands shouldn't be chatty if things go as planned unless requested.$ drush sapi-sisWorks good. I did notice that the error message that is shown when a server ID or index ID is invalid is incomplete. It says "The following servers are defined:" but then doesn't list the servers.
Comment #14
pfrenssenI am stopping for today. I will unassign since this is worked on by multiple people.
We need this in for our project urgently, so if nobody else is going to finish this during the night I will pick this back up tomorrow morning (EU time) and will have this done by tomorrow around noon. I will assign it to me as soon as I start working on it so we won't do duplicate work.
Comment #15
pfrenssen@claudiu.cristea is correct, since this collection of Drush commands is actually a Symfony service it is better to keep it in one single file.
Comment #16
borisson_So both @claudiu.cristea and @pfrenssen commented on the first part of the comment I posted earlier, but you didn't comment on the second part.
I actually would love to see us use this approach. I think this makes sense.
Do both of you agree with this approach (only converted the list command and only tested the drush 8 version).
Also leaving @claudiu.cristea's patch up in the files list. If ya'll disagree we can disregard this approach.
Comment #17
pfrenssenI completely agree with this approach.
@borisson_ what do you think of merging the sapi-status and sapi-list commands? For backwards compatibility they could be aliases of the same command with different defaults for displaying the information.
I'm going to work on moving this forward but I am timeboxed so I might not be able to finish the whole thing. I'll try to get as much done as possible in the time I have.
Comment #18
borisson_They output different things, and I assume they are used in different scenario's. I think we could do that as a followup but for now let's keep them as 2 different commands.
@pfrenssen: as soon as you have a patch I'd be happy to push this on if needed.
Comment #19
pfrenssenThis went a lot deeper than I expected. Since Drush 9 is still very bleeding edge there is a whole herd of unshaven yaks waiting right around the corner when you start prodding the code.
I managed to get the `sapi-l` command working properly for all output formats, but this involved creating my own `OutputFormatter` class in order to support both the inline formats (like 'table' and 'csv') and the structured formats (like 'json' and 'yaml'). I also got XML to work but this requires a patch in consolidation/output-formatters (ref https://github.com/consolidation/output-formatters/pull/60).
Now that we can output data for machine consumption it is important that our commands can output the machine names of the data. Up to now it was only outputting human readable labels, but for automating server jobs we need machine names. So I have extended the data being returned with machine names and defaulted to the human readable fields so that the command still works as before.
It's pretty cool, on the one hand you can get nice human readable data:
But we can also get JSON or YAML for specific data we need in order to automate stuff:
Note that it will be a lot of work to backport this all to Drush 8. I would actually prefer to keep the Drush 8 integration with the new `CommandHelper` service out of this issue and handle it in a followup.
All remarks related to commands other than `sapi-l` is not yet addressed.
Comment #20
borisson_Oh yeah, that would make it too hard. Let's revert the drush 8 portion of this patch.
Comment #21
pfrenssenPorted `drush sapi-en`.
I think we should keep all logging and translation of strings out of `CommandHelper` actually.
Comment #22
borisson_Reset the changes to the drush 8 commands, adds all of the things to drush 9.
I'm actually at home from work because I'm having a fever, so I hope that everything is somewhat ok. Going to write some kernel tests for the service so I'm more confident in the work I did just now.
So please review this very thoroughly.
Comment #23
borisson_Start of the kernel tests for this, not all of them are passing - but I don't really know why.
Comment #25
borisson_Fixed some coding standars thing, I'll try to pick these tests up again tomorrow.
Comment #27
borisson_More testcoverage. Still that one fail that I don't know why.
@drunken monkey any idea why the indexing is not working in this test?
Comment #29
borisson_Comment #31
pfrenssenMaking real good progress @borisson_!
Yesterday evening I was looking into tackling the portability of translations + making logging possible for Drush 8 but I forgot to post my patch.
Here it is, this is against the patch from #21. It's not finished but this is something we can look at after @borisson_ is done with his work. It introduces a new `CommandLogger` which can be used to pass messages between the `CommandHelper` and the calling code. This is conceptually cleaner than setting the logger in every command, and it will also work for Drush 8 which relies on procedural code for logging.
Note that this is just an idea from yesterday evening and is now outdated, I just wanted to post this because I am going to a festival and won't be able to contribute for a few days. #29 is still the current patch!
Comment #32
mpp commentedThanks borisson_, looking good!
Wrt the logging, perhaps you can have a look at how it's done for migrate_tools? See https://www.drupal.org/node/2914005
Comment #33
drunken monkeyShortly looking over this.
Comment #34
drunken monkeyFirst of all, thanks a lot, everyone, for your great effort on this!
Seems this is really important to have for a lot of people, so I'll also be more active here now.
Thumbs up, seems like an awesome idea! I'd love to support Drupal Console, too, but I already get enough complaints about the Drush integration that I'm not using. If all of this uses the same code for the most part, and is properly covered with automated tests, it would make my life considerably easier.
Regarding the latest patch: It generally already looks very good, but I (of course) still have some complaints:
@coverssays it all. (Please point the change/documentation out to me if I'm mistaken.)ExampleContentTraitin the test?namespace Drupal\search_api\Utility;near the end of the test class? Doesn't seem to serve any purpose. (Also, I was actually quite sure this was illegal in PHP. But seems I was mistaken there.)\Drupal\search_api\Commands\SearchApiCommandsnot following all (doc comment) coding standards is on purpose? If the comments are taken as a command definition, then there's of course not really a way around that.CommandHelpershould get one, too. (Then, of course, all type hints (also in doc comments) should be updated to use the interface.)…\Systemor just the parent namespace (for now).I didn't test any of this myself, tbh, I'm not that into Drush et al. I'll just take your word (and the test bot's – yay! \o/) for it once you and a few others say it's RTBC.
Comment #35
borisson_dt-function. Otherwise it doesn't work\Systemsounds better, yeah.This also needs better/more test-coverage still, not all the methods in the utility are covered yet.
Setting to needs review to see if the patch now passes.
Core broke facets rest-integration, and because of that I have branch failures - after I figure that out (#2916212: Fix rest tests.), I'll come back to this issue.
Comment #37
drunken monkey@ 1: #2108785: Remove the requirement for doxygen for test methods. Being discussed for four years now, but still not nearly decided. (You'll also notice I voted against it.)
@ 3:
BackendTestBaseandContentEntityDatasourceTestboth use it.@ 4: Ah, I see … Then maybe just use the root namespace instead, is that possible? Pretty ugly in any case – but probably the refactoring which should cleanly separate the service from Drush will make this obsolete anyways, right?
@ 7: It's not just about allowing others to override the service cleanly, it's also just a matter of coding standards: classes should never be used for type hinting. I.e., if we want to have a type hint (we do), we need an interface.
But feel free to ignore it for now. I'll just add it right before committing and you won't be able to stop me. ;P
@ 9: Looked over it again, and I guess a separate exception could indeed make sense there. Almost all of them are for invalid user input – having a separate exception for that does sound reasonable. (Maybe just not catch
SearchApiExceptionexceptions from elsewhere?) I guess I'm good either way.But one more thing I noticed during that second look: you (or whoever) copy-pasted too much in
disableIndexCommand(), so now the exceptions talk about "enabling".Comment #38
drunken monkeyAh, of course, the missing namespace, like you explained …
However, reverting to what you had before, I actually got syntax errors – exactly like I thought there should be. Didn't have that before, though – very strange.
Anyways, I could only make it work with the block-based namespaces. And the other three tests are still failing.
Comment #40
borisson_The syntax errors are just phpstorm not understanding it. See \Drupal\Tests\Core\Session\AccountProxyTest, \Drupal\Tests\aggregator\Unit\Plugin\AggregatorPluginSettingsBaseTest, (among others in core) where the style I used i also in use.
When looking up examples in core I also saw this style:
That looks much better, but I can't get that to work.
I think I now resolved all the issues already brought up. I also have green tests locally.
Updating the IS with what we still need to do.
Comment #41
borisson_Still to test:
\Drupal\search_api\Utility\CommandHelper::indexItemsToIndexCommand\Drupal\search_api\Utility\CommandHelper::resetTrackerCommand\Drupal\search_api\Utility\CommandHelper::searchIndexCommandThe other methods are tested now.
We still need to find a way to figure out the translations and logging in an abstract manner, but at least this is a decent start.
Comment #42
pfrenssenThe patch from migrate_tools is only supporting Drush and doesn't have an abstracted service to deal with all command line tools so it can just rely on Drush to translate messages.
Since `CommandHelper` is a service we shouldn't set a logger in it on call time, a service is a singleton so the logger will be persisted for all subsequent calls to it, even if it is not coming from the same source. For example a drush command could set `CommandHelper::logger`, but then a hook might fire as part of the drush command, which triggers some other code to call a method on the `CommandHelper` again, but then the logger will still be the one from the drush command. You can see this from the patch that it doesn't work right, the logger needs to be set again and again in every single method that uses something from the CommandHelper.
Basically we have a circular dependency: `SearchApiCommands` depends on `CommandHelper`, but this also depends on `SearchApiCommands` for supplying the logger.
There are two possible solutions, either we reduce the functionality of `CommandHelper` to the bare minimum, and keep all the logging and translation out of it, doing the loops and logic in `SearchApiCommands`.
The other solution is to not make `CommandHelper` a service, but a regular object that is persisted on the `SearchApiCommands` object instead of on the shared container. We can instantiate it at calltime:
Unfortunately I won't be able to work on this any more for the time being, I've been assigned to another ticket at work.
Comment #43
drunken monkeyThanks a lot for your continued work on this!
The syntax errors were not just in PhpStorm, but also when running the tests. Otherwise, I probably wouldn't have said anything.
Anyways, it's clear I was completely mistaken, and the PHP docs also list this as discouraged but entirely valid, so sorry for the (small/potential) confusion. I'd still like to get rid of it, if possible, and otherwise the function at least needs some documentation, but hopefully any translation/logging solution you come up with will take care of that.
Would of course be awesome if Drush itself could include something to help with this problem which, after all, many modules will probably face. Is there maybe already an issue for that, or do we want to create one?
Regarding the problem explained in #42: Is this really a valid scenario? As I understood it, the new service was just for use by the various console interfaces (i.e., Drush and Drupal Console), not for any other part of the code to call. So, having a hook invocation lead to a call to the service doesn't seem like something that could happen, or that we want to support. A request that involves the command helper will always be initiated by either Drush or Drupal Console – or, potentially, even some other application – but then that request will always be "owned" by that specific application. When you execute a Drush command, you want that whole request logged via Drush. And we don't want to use the command service for any part of the framework – it's just a one-way interface from CLI applications to the framework.
Or did I misunderstand the problem? (Or miss something else?)
Comment #44
pfrenssenYes if this is a service then it is available by the full Drupal ecosystem and everybody can call its methods whenever they want. And it's methods are really handy too, if I need to clear a search index I can just call:
If I turn the question around I can let you answer it yourself :)
Should CommandHelper be a full lazy loaded service that is available on the container so it can be used by the entire Drupal API?
So yeah, if you want it to be used only by CLI tools, then don't make it a global service.
Comment #45
borisson_Looks like the search method doesn't do actual searching (or at least it doesn't in the test). The result count is correct, but the results aren't added to the result items.
I also fixed the other things that needed tests, I also fixed #42/ #44.
Comment #47
borisson_@drunken monkey: if we end up using this patch (or something like it), can we also credit @bircher for the inspiration?
@pfrenssen: Does the latest patch address your concerns about the service?
Comment #48
mpp commentedThe logger isn't added yet: PHP Catchable fatal error: Argument 1 passed to Drupal\search_api\Utility\CommandHelper::setLogger() must implement interface Psr\Log\LoggerInterface, null given, called in web/modules/contrib/search_api/src/Commands/SearchApiCommands.php on line 28 and defined in vendor/psr/log/Psr/Log/LoggerAwareTrait.php on line 22
Shouldn't we also inject entity_type.manager & module_handler?
Comment #49
borisson_We can't use the logger from the
__constructfor some reason. Fixes #48.Comment #51
pfrenssenLooks great now! Thanks!
Comment #53
drunken monkeyComment #54
drunken monkeyReviewed this and worked on it a bit, but I now realize it's probably still a bit away from being considered RTBC?
Anyways, I hope the changes and my comments below are still helpful.
@todocomments in the patch. Do you intend to still work on those, or do you want to add the code with those unresolved?dt()in the code seems important. It would really be nice to get rid of that hack in the test file – especially if it's gonna turn the whole file red in my PhpStorm. DX--.resetTrackerCommand()method took datasource IDs, not entity types. It would be more flexible regarding non-entity datasources and also keep the code simpler. We might to provide a way to get a list of datasource IDs (for an index), though.SearchApiCommandsmethods take a single ID, but theCommandsHelpercan accept multiple ones? Seems to me that's a) not necessary and leads, in its current form, to the ugly[NULL]special case.listCommand()have options which are then ignored?search_api.drush.incfile with calls to the new helper class?The test was failing because you're using the test backend for the server, which doesn't do an actual search (of course). See
\Drupal\search_api_test\Plugin\search_api\backend\TestBackend::search().@ #49: How should
$this->loggerbe already available in the constructor?Comment #55
borisson_But yeah, this is definitely not done yet, I'd like to spend more time on this. Hopefully this patch pushes things in the right direction.
I now added translations to the exceptions - not sure if we should leave those untranslated.
This patch removes some of the todo's where they were no longer relevant.
Comment #56
drunken monkeyAwesome, thanks a lot! Looks a lot better already.
I fear the current translation code will have the same problem I described in #2917041: logException() trait method (probably) not working with translation – i.e., the translatable strings won't get properly extracted that way. I think you should either always do
$t = $this->translationMethod;in methods where you use it, or just provide at()method on the object which uses that property. Then, I think, this should be detected properly.In the rest of the module, as also specified in the coding standards, exception messages are not translated. However, with Drush, when they directly refer to illegal values passed by the user, it seems they could also count as "user-facing", so probably they should be translated, yes.
Doing the Drush 8 migration to use the new helper class in a follow-up would be fine, if someone says they'll definitely work on it soon and get that sorted out. Otherwise, we'll end up with two duplicate sets of code to maintain. (On the other hand: I guess Drush 8 will reach EOL soon, then, so I guess we could then also remove that integration? Might also be OK, depending on the time frame.)
Anyways, thanks for your reply and your continued work! Then I guess, just set it to RTBC when you find you're finished (and another person has already reviewed) and I'll review it again.
Comment #57
borisson_Also ported the drush 8 commands.
Comment #58
borisson_Fix cs issues for drush 8 code.
Comment #59
mpp commentedI missed this one: the use of these braces is supported by PHP7 only and won't work on PHP5.6:
See http://php.net/manual/en/migration70.incompatible.php
Should I open a new ticket?
Comment #60
borisson_Nah, this is not committed yet - so we should fix it here. I knew this solution was too good to be true. Do you happen to know what the php5.6 compatible solution is?
It would also be super awesome if you could test the patch and verify that it works. We really should get this in before we tag a new release. Drush 9 usage will only go up.
Comment #61
borisson_Comment #62
mpp commentedThis should work:
I'll test the patch.
Comment #63
mpp commentedAdded patch for PHP5.6 compatibility.
@borisson_: Tested all commands individually with success!
Comment #64
mpp commentedAttached another patch that solves the PHP56 issue by using call_user_func_array() instead of an intermediary variable.
I suggest we refactor these calls to a private class helper translate()?
Comment #65
borisson_Yeah - that sounds like a great idea! That would make this easier, let's make a new method:
Comment #66
mpp commentedComment #68
mpp commentedAdded translation helper().
Comment #69
mpp commentedAdded translation helper().
Comment #70
borisson_Thomas, can you have a look at the latest patch?
Comment #71
drunken monkeyThanks a lot, great job!
Regarding the translation helper problem, you apparently didn't notice my paragraph on that in #56:
Changed the method name to
t(), accordingly.Otherwise, I mostly cleaned up the doc comments and (to a smaller extent) the code. I also got rid of all the
setLogger()calls in every single command method – just setting it in the command class'ssetLogger()method should do the job just as well.…\Consolidation\OutputFormattersnamespace, with just a single class (in two directories)? Couldn't that live in an existing namespace – probablyContrib?Comment #72
mpp commentedRefactored variables, arguments & parameters to snake_case; with one exception in RowsOfMultiValueFields but the RenderCellInterface requires camelCase:
Comment #73
mpp commentedMoved RowsOfMultiValueFields into contrib.
Comment #74
jhedstromI'm seeing this notice when running with this patch:
So the patch should probably be updated to specify these services.
Comment #75
pfrenssenNote that this notice that @jhedstrom mentions will only appear when you use the new Drush 9.0.0-rc1 release.
Comment #76
drunken monkey@ mpp: Thanks a lot, great work!
@ #74: Thanks for testing! Does the attached patch resolve that problem?
Comment #77
sylvainm commentedYes the notice has disappeared with this new version, thanks
I tested those commands and they work great :
* sapi-c
* sapi-l
* sapi-i
Comment #78
drunken monkeyThanks for your feedback!
Not sure anymore: Was this RTBC then? Does someone else want to review? Or is there still something to do?
Comment #79
sylvainm commentedI think it is ok, it was RTBC in #70
Comment #81
drunken monkeyOK, then. Good to hear.
Committed.
Thanks a lot again, everyone, for all your hard work in here!