Problem/Motivation
In Drupal\migrate\Plugin\MigrateMessageInterface, getMessageIterator() is declared as returning \Iterator. According to the PHP page on Iterator, that means the return value should implement five methods, including rewind().
As discussed in #2714529-29: Add source and destination IDs to the data returned by getMessageIterator() , the implementation of getMessageIterator() in Drupal\migrate\Plugin\migrate\id_map\Sql returns an object of class Drupal\Core\Database\Statement, which does not implement rewind().
Proposed resolution
Since this is a public interface, we do not have the option of changing the return type. See the discussion in #5 and #6. Instead, we will add a new method that declares its return value as \Traversable and deprecate the old method.
Completed tasks
- Add a new method
MigrateMessageInterface::getMessages()that duplicatesgetMessageIterator()except that the doc block reads@return \Traversable. See the patch in #2. - In
Drupal\migrate\Plugin\migrate\id_map\SqlandDrupal\migrate\Plugin\migrate\id_map\NullIdMap, copy the implementation ofgetMessageIterator()to implement the new methodgetMessages(). - Make both implementations of
getMessageIterator()wrappers forgetMessages(). - Add a deprecation notice to
getMessageIterator(). See Drupal core deprecation policy. - Search for uses of
getMessageIterator()and replace them withgetMessages(). For example,grep -ri getMessageIterator core. - Add a change record. See Contributor task: Write up a change record for a Drupal core issue.
- Add a release notes snippet to this issue description.
- Reroll the patch from #18. See Rerolling patches or Contributor task: Re-roll a Drupal core patch.
Remaining tasks
User interface changes
None
API changes
This is an API change, since MigrateMessageInterface::getMessageIterator() is a public function.
Data model changes
None
Release notes snippet
The method getMessageIterator() from Drupal\migrate\Plugin\MigrateMessageInterface is now deprecated. Use getMessages() instead.
| Comment | File | Size | Author |
|---|---|---|---|
| #46 | interdiff.txt | 801 bytes | ghost of drupal past |
| #46 | 3054167_46.patch | 18.82 KB | ghost of drupal past |
| #18 | 3054167-18.patch | 15.49 KB | christinlepson |
Comments
Comment #2
christinlepson commentedPatch to change the doc block to read
@return \Traversableand change the return description from "Retrieves an iterator over the message rows." to "Retrieves a traversable object of the message rows."Comment #3
benjifisher@clepson:
Thanks for taking this on!
When you add a patch to an issue, you should change the status to "Needs review" (NR) to let people know that the issue is ready for the next step. I will do that for you, and I will give a review in a day or two unless someone else does it first.
Comment #4
benjifisherThe patch in #2 does what the issue suggests. It also does a little more, adjusting the description to match. (Kudos!)
Now we have to decide whether this is the right thing to do. This part is not a novice task, so I am removing that tag.
As far as I can tell, there are two classes that implement this interface, both in the
Drupal\migrate\Plugin\migrate\id_mapnamespace:SqlandNullIdMap.Sql::getMessageIterator()returns an object of classDrupal\Core\Database\Statement, which implementsStatementInterface, which extends\Traversable: so far, so good.NullIdMap::getMessageIterator()returnsnew \ArrayIterator([]). That class implements\SeekableIterator, which extends\Iterator, which extends\Traversable.I think the current approach is the minimal fix to get this working.
While working on #2714529: Add source and destination IDs to the data returned by getMessageIterator() , I also noticed that some of the tests (see
MigrateSkipRowTest) assume thatSql::getMessageIterator()returns aStatementobject. (They call thefetchAll()method on the result.) I think it is out of scope for this issue, but we could eitherSql::getMessageIterator()implementsDrupal\Core\Database\StatementInterfaceI think that (1) is a terrible idea, but I bring it up for the sake of discussion. I am not sure that (2) is allowed in PHP, but I think it is; if so, then I think it is a good idea. I might even be convinced that it is in scope for this issue.
Comment #5
alexpottSo I think we have a problem with getMessageIterator() returning a something other than an iterator. I think we should go a step further here and add a new method getMessages() and that returns a traversable and deprecate getMessageIterator() in favour of getMessages(). I've looked at contrib and there's no one implementing this interface - http://grep.xnddx.ru/search?text=MigrateIdMapInterface&filename=&page=3
Comment #6
benjifisherI guess the problem is that this solution violates the backwards compatibility (BC) policy: https://www.drupal.org/core/d8-bc-policy#interfaces.
I will add a new proposed resolution to the issue summary. If I do a good job of that, then I think I can restore the Novice tag.
The BC policy mentions that this change should be mentioned in the release notes, so I am adding a section to the issue summary for a snippet.
Comment #7
heddnI'm +1 to deprecateing
getMessageIteratorand adding a newgetMessagesmethod. There are few live custom implementations of ID maps and all that I'm aware of do not focus on messaging but other parts of the ID map.Comment #8
mglamanAs someone who has done a few custom ID maps, the work was never around messages but altering the SQL table, see https://glamanate.com/blog/migrationwtf-specified-key-was-too-long-max-k...
Comment #9
christinlepson commentedWorking on it now, just need to write the change record.
Comment #10
christinlepson commentedThink I covered everything other than adding release notes to issue description.
Comment #11
heddnWe still need implicit test coverage of the deprecated method.
Comment #12
christinlepson commented@heddn So would I write unit tests for the two usages of the deprecated methods (in Sql and NullIdMap) to ensure that the correct deprecation message is displayed?
I'm not sure what you mean by implicit test coverage (I'm new, sorry).
Comment #13
heddnThanks for your contributions. Unit tests are perfect, just like you described. There's an @expectedDeprecation annotation on tests that should help here. Search the code for other examples.
Comment #14
benjifisher@clepson:
I would use just the interface name and the method in the title of the change record (CR): something like "In MigrateMessageInterface, getMessageIterator() is deprecated in favor of getMessages()". The body of the CR should contain the fully qualified name.
I am not sure whether there are any guidelines on titles for CRs, but when I browse the recently published ones, I see only a few that use fully qualified names. Some, like "\Drupal\Core\Validation\TranslatorInterface no longer extends \Symfony\Component\Translation\TranslatorInterface", would be hard to understand without the full name. I do not think that MigrateMessageInterface has much potential for confusion.
Can you also add some before and after code snippets to the CR? You can use something like
as the source of the example.
I do not have time for a full review now, but while looking for that example, I noticed that the new method is
getMessage()instead ofgetMessages(), as suggested in #5.Comment #15
christinlepson commentedDrupal\Tests\migrate\Unit\MigrateSqlIdMapTestandDrupal\Tests\migrate\Unit\MigrateNullIdMapTestgetMessage()togetMessages()as mentioned in #14getMessages()docs description to read "Retrieves a traversable object of messages related to source records."Comment #16
christinlepson commentedComment #17
benjifisherI searched core for
getMessageIteratorand only found it in the expected places: two new deprecation tests, two IdMap plugins (where it is a wrapper forgetMessages()), and the interface. So far, so good!My only complaint are that the deprecation tests are more complicated than they have to be:
The point of this test is to check that we get a deprecation message when we call
getMessageIterator(), so I think the first and third lines are all we need. Unless you already tried that and I am wrong.Also, the test class extends MigrateTestCase. I did not try it, but I think that
$this->getIdMap()->getMessageIterator()should work.Same idea here. I think all we need is
$messages = $this->getIdMap()->getMessageIterator();. The rest of this test more or less duplicatestestMessageSave().I edited the change record a bit.
I am updating the issue summary and un-assigning the issue. (You should un-assign yourself at the same time that you mark the issue NR.)
Comment #18
christinlepson commented@benjifisher you are absolutely right. Simplified the tests to only check for deprecation.
Comment #19
christinlepson commentedComment #20
benjifisher@clepson:
This looks perfect. Nice work!
I checked https://www.drupal.org/pift-ci-job/1320859, showed all (passing) tests, and verified that the two
testGetMessageIteratortests are listed.I updated the issue summary and added a snippet for the release notes. Back to RTBC.
Comment #22
alexpottComment #24
mikelutzComment #26
benjifisherComment #27
mikelutzComment #28
benjifisherThis issue needs a reroll because #2714529: Add source and destination IDs to the data returned by getMessageIterator() (the issue I was working on when I created this one---see the issue summary) was fixed.
Doing the reroll is a novice task, so I am adding that label again.
Comment #29
mikelutzComment #30
shubham.prakash commentedComment #31
shubham.prakash commentedThis patch should fix the issue.
Comment #32
shubham.prakash commentedThis patch will fix the issue.
Comment #34
shubham.prakash commentedAgain.
Comment #36
benjifisher@shubham.prakash:
Thanks for taking this on! I compared your patch to the one in #18.
When I added the Novice tag, I should have added to the issue summary a link to the instructions for rerolling a patch. I will do that now.
The main problem with your patch (probably the reason it fails automated tests) is that you remove the
getMessageIterator()method entirely, instead of making it a wrapper for the newgetMessages()method. There are some other, more minor problems:This introduces an indentation error.
We only need one "blank" line here.
This adds an unneeded blank line.
Comment #37
shubham.prakash commentedThank you @benjifisher
Can you review this patch, I made the required changes.
Comment #38
andypost@shubham.prakash please add interdiff of changes https://www.drupal.org/documentation/git/interdiff it's really hard to follow changes you made
Comment #40
benjifisherSince this issue deprecates an existing method, I think we should add the @deprecated tag.
Comment #41
init90This should fix test failure.
Also, I've changed the deprecation format to adopted in: Adopt consistent deprecation format for core and contrib deprecation messages
And renamed test which was added here: Add source and destination IDs to the data returned by getMessageIterator() from
testGetMessageIterator()totestGetMessages().Comment #42
heddnThis looks good. Full test coverage in place.
Comment #43
benjifisher@init90:
Thanks for the link to #3024461: Adopt consistent deprecation format for core and contrib deprecation messages. I was not aware of that standard.
Good catch on updating the test added in #2714529: Add source and destination IDs to the data returned by getMessageIterator() . That is the issue that made the patch in #18 fail.
Interdiffs do not work well for rerolls, so I looked at a raw diff between the patches in #18 and #41. (More precisely, I compared them using diff mode in Vim.) +1 for RTBC.
I am updating the "Remaining tasks" section of the issue summary and removing two tags now that the reroll is done.
Tip: use
[# 3024461](without the space character) to generate links to other issues.Comment #44
ghost of drupal pastCouple problems I found:
Comment #46
ghost of drupal pastAh, one more iterator_to_array.
Comment #47
heddnLooks good again.
Comment #48
larowlanthere's a couple more fetchAll calls here in tests, should we be removing them too as per #44?
Other than that, looks good to me - nice work folks
Comment #49
benjifisherIt seems to me that the last two patches have expanded the scope of this issue.
Earlier patches aimed to make the minimal changes in order to get an honest
@returncomment. Given that this issue already involves a new API function and a deprecation, my inclination is to follow that minimalist approach.The last two patches additionally update existing tests so that they no longer call
fetchAll(). Since we are testing an implementation of the interface that actually returns an object of Drupal\Core\Database\Statement, it is not clear to me that we have to do that at all, let alone in this issue. In fact, it seems odd to me to avoid usingfetchAll(), but then to assume that the Traversable items are objects with amessageproperty. Let's face it, PHP is not a strongly typed language.If we are going to expand the scope to removing calls to
fetchAll(), then we should say so in the issue summary. If we are not going to expand the scope, then we could go back to the patch in #41, which was already RTBC.Comment #50
alison(taking a look at this issue b/c mentioned in Slack weekly #migration meeting)
I feeeeeel like re-narrowing the scope and opening a separate issue for removing
fetchAll()seems like the best path, esp because it looks like there might be a conversation to be had about whether or not to removefetchAll()anyway?Just my two cents, and/or, a bump for the thread to nudge prior patch authors to chime in if they wish.
Comment #51
larowlanFWIW I'm happy if the answer is 'some of the fetchAll calls in tests are providing implicit coverage for the SQL implementation' I was just posing the question. If that's the case, feel free to put it back to RTBC as is.
I think the changes in #44 provide coverage that the return is indeed an iterator.
Comment #52
heddnI think the patch is reasonably sized. We've now got implicit coverage of both approaches. Let's just take it as-is.
Comment #53
larowlanComment #54
larowlanThanks folks, agree.
Committed 68c0a25 and pushed to 8.8.x. Thanks!
Comment #55
larowlanpublished change record