Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHPLIB-954: Add return types to all methods #1391

Merged
merged 5 commits into from
Sep 24, 2024

Conversation

alcaeus
Copy link
Member

@alcaeus alcaeus commented Sep 12, 2024

PHPLIB-954

This PR:

  • adds testing with the 2.0 branch for PHPC,
  • adds native return types for all methods, removing ReturnTypeWillChange attributes where present
  • replaces all Cursor types with CursorInterface
  • removes the compatibility layer introduced for the CursorId deprecation

Copy link
Member Author

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some explanations. A number of the psalm errors are due to vimeo/psalm#10019, which doesn't correctly infer the return type or (object) ['foo' => 'bar'] as stdClass but instead assumes object. I'll take a look at the other psalm errors regarding codec generics, but feel free to leave feedback in the meantime.

* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function aggregate(array $pipeline, array $options = [])
public function aggregate(array $pipeline, array $options = []): CursorInterface&Iterator
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have any plans for this yet, but I propose having CursorInterface extend Iterator to avoid the need for an intersection type here. Currently, only the Cursor class implements Iterator (added in PHPC-1691, but not added to CursorInterface due to BC constraints).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CursorInterface already extends Traversable, which is better IMO. We should not require the Iterator interface for custom cursor classes.
In case people really need the Iterator API, they can wrap it in an IteratorIterator.

Suggested change
public function aggregate(array $pipeline, array $options = []): CursorInterface&Iterator
public function aggregate(array $pipeline, array $options = []): CursorInterface

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A CursorInterface type without an intersection with Iterator won't allow you to call $cursor->next(); - that's an issue we faced in ODM. Ideally, we'd fix this in PHPC by having CursorInterface extend Iterator, but until then we're stuck with this solution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is always solutions to wrap a Transversable that is not an Iterator.
With a Generator (see UnrewindableIterator, IteratorIterator or IteratorAggregate::getIterator()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Providing some additional context and throwing in my two cents:

  • We added Iterator to Cursor in PHPC-1691 in order to comply with PHP 8.
  • CursorInterface was introduced in PHPC-1123 to allow other classes to fill in for a Cursor, which cannot be extended. AFAIK, the only existing use case for this within our own driver is CodecCursor.
  • CodecCursor currently implements both CursorInterface and Iterator, so that would not be negatively impacted by this change.

While conditionally wrapping a CursorInterface to get access to Iterator methods is always possible, it may be tedious. Given that CursorInterface is intended to be used for classes that compose a Cursor, it seems a small ask for the wrapping class to also implement Iterator.

I'm not sure what the use case would be for a CursorInterface implementation to rely on IteratorAggregate, as it would then have no way to influence the inner Cursor's iteration. Hypothetically, it could proxy other methods (e.g. toArray()), but I've never encountered such an implementation in the wild.

If having CursorInterface extend Iterator doesn't negatively impact PHPLIB, Doctrine ODM, and the Laravel integration, I wouldn't be too concerned about other use cases. Worst case, we're asking users to implement a implement a few extra methods (easily accomplished with a trait if needed).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Added PHPC-2447 to track this.

I'll note that we shouldn't implement IteratorAggregate, as that would suggest one can obtain multiple iterators from a single cursor. As a cursor can't be rewound and may only ever yield a single iterator, I don't think we should consider implementing IteratorAggregate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CursorInterface was changed to extend Iterator, and this PR now includes changes for PHPLIB-1114, using CursorInterface where possible.

@alcaeus alcaeus requested review from jmikola and GromNaN September 13, 2024 07:06
@alcaeus alcaeus marked this pull request as ready for review September 13, 2024 07:06
@alcaeus alcaeus requested a review from a team as a code owner September 13, 2024 07:06
@alcaeus alcaeus force-pushed the phplib-954-add-return-types branch from 7adcc67 to 062b5db Compare September 13, 2024 08:21
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function aggregate(array $pipeline, array $options = [])
public function aggregate(array $pipeline, array $options = []): CursorInterface&Iterator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CursorInterface already extends Traversable, which is better IMO. We should not require the Iterator interface for custom cursor classes.
In case people really need the Iterator API, they can wrap it in an IteratorIterator.

Suggested change
public function aggregate(array $pipeline, array $options = []): CursorInterface&Iterator
public function aggregate(array $pipeline, array $options = []): CursorInterface

@alcaeus alcaeus requested review from GromNaN and jmikola September 16, 2024 11:16
@alcaeus alcaeus force-pushed the phplib-954-add-return-types branch from a903ddc to f731e0f Compare September 16, 2024 11:16
jmikola
jmikola previously approved these changes Sep 16, 2024
Copy link
Member

@jmikola jmikola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional suggestions.

Decide how to handle the CI warnings, but LGTM.

@alcaeus
Copy link
Member Author

alcaeus commented Sep 20, 2024

Updated the PR. This currently includes changes from #1427, but I'll wait until that PR has been merged up to 2.x and rebasing this PR to preserve proper history.

@alcaeus alcaeus force-pushed the phplib-954-add-return-types branch from 6a4681b to 9864dbc Compare September 20, 2024 08:10
@alcaeus alcaeus requested a review from jmikola September 20, 2024 08:11
@alcaeus alcaeus dismissed jmikola’s stale review September 20, 2024 08:11

Significant changes since review

*/
private function executeAggregate(Server $server)
private function executeAggregate(Server $server): CursorInterface
{
addSubscriber($this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing relevant to this PR, but I want to point out that it's a bit awkward that we can assign subscribers to Managers but not individual Servers. That forces us to use a global subscriber here.

I suppose we could add Server::getManager() to work around that 🤷‍♂️

@alcaeus alcaeus requested a review from jmikola September 23, 2024 07:09
@alcaeus alcaeus force-pushed the phplib-954-add-return-types branch from df78dcf to 17352ee Compare September 23, 2024 07:22
@@ -720,7 +720,7 @@ public function testInitialCursorIsNotClosed(): void
* reports the cursor as alive. While the cursor ID is accessed through
* ChangeStream, we'll need to use reflection to access the internal
* Cursor and call isDead(). */
$this->assertNotEquals('0', (string) $changeStream->getCursorId(true));
$this->assertNotEquals(0, $changeStream->getCursorId());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make the test more robust if you don't rely on int cast?

Suggested change
$this->assertNotEquals(0, $changeStream->getCursorId());
$this->assertNotEquals(new Int64(0), $changeStream->getCursorId());

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't make a difference, as the custom Int64Comparator will always handle these assertions, and it leverages the comparison behaviour implemented in Int64 directly.

$previousCursorId = $changeStream->getCursorId(true);
$this->forceChangeStreamResume();
$previousCursorId = $changeStream->getCursorId();
$this->forceChangeStreamResume($secondary);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this method previously created the fail point on the primary server, instead of on the secondary server where the changestream was created. This meant that the change stream was never resumed and the cursor ID was the same as before. We just didn't catch this mistake as the assertNotSame comparison always saw the objects as different as they didn't have the same identity. Lessons learned...

Copy link
Member

@GromNaN GromNaN Sep 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be fixed on the 1.x branch, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted to #1434. Will rebase when that PR is merged.

Squashed commit of the following:

commit bc37a4b83e86edba06f97148d9a1b4a194623097
Author: Andreas Braun <[email protected]>
Date:   Thu Sep 19 13:32:18 2024 +0200

    TMP: Use branch reporting 2.0 version for testing

commit 938c4cd5be825b605a01e1f3129a2e233c62ac1b
Author: Andreas Braun <[email protected]>
Date:   Wed Sep 18 10:49:01 2024 +0200

    Update CI config to test with ext-mongodb 2.0

commit 23b11ec
Author: Andreas Braun <[email protected]>
Date:   Wed Sep 18 10:47:33 2024 +0200

    Require ext-mongodb 2.0
@alcaeus alcaeus force-pushed the phplib-954-add-return-types branch from 1511aa6 to 7c987aa Compare September 24, 2024 07:02
@alcaeus alcaeus enabled auto-merge (squash) September 24, 2024 07:03
Squashed commit of the following:

commit b06bffe
Author: Andreas Braun <[email protected]>
Date:   Thu Sep 19 12:56:07 2024 +0200

    Update psalm baseline

commit bb4bb56
Author: Andreas Braun <[email protected]>
Date:   Thu Sep 19 12:55:52 2024 +0200

    Remove CursorInterface::getId compatibility layer

commit 00fa5e4
Author: Andreas Braun <[email protected]>
Date:   Thu Sep 19 12:55:32 2024 +0200

    Add temporary stubs for cursor classes in 2.x
@alcaeus alcaeus force-pushed the phplib-954-add-return-types branch from 7c987aa to 16547cd Compare September 24, 2024 07:16
@alcaeus alcaeus merged commit 5dda098 into mongodb:v2.x Sep 24, 2024
31 checks passed
@alcaeus alcaeus deleted the phplib-954-add-return-types branch September 24, 2024 08:00
alcaeus added a commit that referenced this pull request Sep 25, 2024
* v2.x:
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
alcaeus added a commit that referenced this pull request Sep 25, 2024
* v2.x:
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
alcaeus added a commit that referenced this pull request Sep 25, 2024
* v2.x:
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
alcaeus added a commit that referenced this pull request Sep 30, 2024
* v2.x:
  PHPLIB-1518 `WriteResult::get*Count()` always return an int on acknowledged result (#1454)
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
alcaeus added a commit that referenced this pull request Oct 16, 2024
* v2.x:
  PHPLIB-1546 and PHPLIB-1159: Remove CreateCollection flags and autoIndexId options (#1478)
  PHPLIB-1227 Use void return types for operations without meaningful result document (#1468)
  Remove deprecated functionality (#1439)
  PHPLIB-1518 `WriteResult::get*Count()` always return an int on acknowledged result (#1454)
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
nicolas-grekas added a commit to symfony/symfony that referenced this pull request Oct 22, 2024
…db v2 (GromNaN)

This PR was merged into the 5.4 branch.

Discussion
----------

[HttpFoundation][Lock] Ensure compatibility with ext-mongodb v2

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | -
| License       | MIT

The extension `mongodb` and the library `mongodb/mongodb` will soon have a version 2.0 that brings breaking changes (see [extension changes](https://jira.mongodb.org/browse/PHPC-2445) and [library changes](https://jira.mongodb.org/browse/PHPLIB-1332)). This PR ensures compatibility with the upcoming version for Symfony 5.4.

- Return types added to `MongoDB\Collection::updateOne()`, the closure in the mock `willReturnCallback` must return an object. mongodb/mongo-php-library#1391
- `MongoDB\Driver\Exception\WriteException` removed in favor of `BulkWriteException` mongodb/mongo-php-driver#1685. No need to keep catching `WriteException` since a the driver bulk API have always be used.
- `float` support to construct `MongoDB\BSON\UTCDateTime` is removed mongodb/mongo-php-driver#1709

Commits
-------

81366bf Ensure compatibility with mongodb v2
alcaeus added a commit that referenced this pull request Oct 29, 2024
* v2.x:
  PHPLIB-1546 and PHPLIB-1159: Remove CreateCollection flags and autoIndexId options (#1478)
  PHPLIB-1227 Use void return types for operations without meaningful result document (#1468)
  Remove deprecated functionality (#1439)
  PHPLIB-1518 `WriteResult::get*Count()` always return an int on acknowledged result (#1454)
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
alcaeus added a commit that referenced this pull request Nov 4, 2024
* v2.x:
  Regenerate evergreen configuration (#1503)
  PHPLIB-1546 and PHPLIB-1159: Remove CreateCollection flags and autoIndexId options (#1478)
  PHPLIB-1227 Use void return types for operations without meaningful result document (#1468)
  Remove deprecated functionality (#1439)
  PHPLIB-1518 `WriteResult::get*Count()` always return an int on acknowledged result (#1454)
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
alcaeus added a commit that referenced this pull request Feb 28, 2025
* v2.x:
  Add return type hint for Encoder::encode() implementation
  Reverse pipeline init from an array (#1596)
  PHPLIB-1617 Accept a Pipeline instance in aggregate and watch methods (#1580)
  Fix CS
  Require latest python version (#1564) (#1565)
  Update src/Operation/Find.php
  Ignore `disableMD5` option as `md5` field is removed from the spec (#1502)
  Remove obsolete baseline entries
  Regenerate evergreen configuration (#1503)
  PHPLIB-1546 and PHPLIB-1159: Remove CreateCollection flags and autoIndexId options (#1478)
  PHPLIB-1227 Use void return types for operations without meaningful result document (#1468)
  Remove deprecated functionality (#1439)
  PHPLIB-1518 `WriteResult::get*Count()` always return an int on acknowledged result (#1454)
  PHPLIB-954: Add return types to all methods (#1391)
  PHPLIB-797: Remove unused methods in UnsupportedException (#1436)
  Revert "Add final annotations to non-internal Operation classes (#1410)"
  PHPLIB-953 Make internal classes and Operation classes final (#1392)
  PHPLIB-1218 Remove deprecated fields from GridFS files (#1398)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants