diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 7e99f32d6..d17c6e9cf 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -5,11 +5,7 @@
name]]>
-
-
-
-
@@ -23,6 +19,9 @@
+
+
+
@@ -184,9 +183,6 @@
-
-
-
@@ -339,6 +335,15 @@
+
+
+
+
+ ]]>
+
+
+ ]]>
+
cursor->nextBatch]]>
@@ -354,11 +359,6 @@
current()]]>
-
-
-
-
-
@@ -713,18 +713,6 @@
value ?? null) : null]]>
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/psalm.xml.dist b/psalm.xml.dist
index 83d825d51..d9640583b 100644
--- a/psalm.xml.dist
+++ b/psalm.xml.dist
@@ -21,6 +21,8 @@
+
+
diff --git a/src/ChangeStream.php b/src/ChangeStream.php
index 55f25b031..f57bcc873 100644
--- a/src/ChangeStream.php
+++ b/src/ChangeStream.php
@@ -21,7 +21,6 @@
use MongoDB\BSON\Document;
use MongoDB\BSON\Int64;
use MongoDB\Codec\DocumentCodec;
-use MongoDB\Driver\CursorId;
use MongoDB\Driver\Exception\ConnectionException;
use MongoDB\Driver\Exception\RuntimeException;
use MongoDB\Driver\Exception\ServerException;
@@ -33,10 +32,6 @@
use function assert;
use function call_user_func;
use function in_array;
-use function sprintf;
-use function trigger_error;
-
-use const E_USER_DEPRECATED;
/**
* Iterator for a change stream.
@@ -88,12 +83,8 @@ class ChangeStream implements Iterator
*/
private bool $hasAdvanced = false;
- /**
- * @see https://php.net/iterator.current
- * @return array|object|null
- */
- #[ReturnTypeWillChange]
- public function current()
+ /** @see https://php.net/iterator.current */
+ public function current(): array|object|null
{
$value = $this->iterator->current();
@@ -106,26 +97,9 @@ public function current()
return $this->codec->decode($value);
}
- /**
- * @return CursorId|Int64
- * @psalm-return ($asInt64 is true ? Int64 : CursorId)
- */
- #[ReturnTypeWillChange]
- public function getCursorId(bool $asInt64 = false)
+ public function getCursorId(): Int64
{
- if (! $asInt64) {
- @trigger_error(
- sprintf(
- 'The method "%s" will no longer return a "%s" instance in the future. Pass "true" as argument to change to the new behavior and receive a "%s" instance instead.',
- __METHOD__,
- CursorId::class,
- Int64::class,
- ),
- E_USER_DEPRECATED,
- );
- }
-
- return $this->iterator->getInnerIterator()->getId($asInt64);
+ return $this->iterator->getInnerIterator()->getId();
}
/**
@@ -255,7 +229,8 @@ private function onIteration(bool $incrementKey): void
* have been received in the last response. Therefore, we can unset the
* resumeCallable. This will free any reference to Watch as well as the
* only reference to any implicit session created therein. */
- if ((string) $this->getCursorId(true) === '0') {
+ // Use a type-unsafe comparison to compare with Int64 instances
+ if ($this->getCursorId() == 0) {
$this->resumeCallable = null;
}
diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php
index 721c59734..88f47f304 100644
--- a/src/Model/ChangeStreamIterator.php
+++ b/src/Model/ChangeStreamIterator.php
@@ -17,7 +17,6 @@
namespace MongoDB\Model;
-use Iterator;
use IteratorIterator;
use MongoDB\BSON\Document;
use MongoDB\BSON\Serializable;
@@ -49,7 +48,7 @@
*
* @internal
* @template TValue of array|object
- * @template-extends IteratorIterator&Iterator>
+ * @template-extends IteratorIterator>
*/
final class ChangeStreamIterator extends IteratorIterator implements CommandSubscriber
{
@@ -77,18 +76,17 @@ public function current()
}
/**
- * Necessary to let psalm know that we're always expecting a cursor as inner
- * iterator. This could be side-stepped due to the class not being final,
- * but it's very much an invalid use-case. This method can be dropped in 2.0
- * once the class is final.
+ * This method is necessary as psalm does not properly set the return type
+ * of IteratorIterator::getInnerIterator to the templated iterator
*
- * @return CursorInterface&Iterator
+ * @see https://github.com/vimeo/psalm/pull/11100.
+ *
+ * @return CursorInterface
*/
- final public function getInnerIterator(): Iterator
+ public function getInnerIterator(): CursorInterface
{
$cursor = parent::getInnerIterator();
assert($cursor instanceof CursorInterface);
- assert($cursor instanceof Iterator);
return $cursor;
}
@@ -173,18 +171,10 @@ public function valid(): bool
/**
* @internal
- * @psalm-param CursorInterface&Iterator $cursor
+ * @psalm-param CursorInterface $cursor
*/
public function __construct(CursorInterface $cursor, int $firstBatchSize, array|object|null $initialResumeToken, private ?object $postBatchResumeToken = null)
{
- if (! $cursor instanceof Iterator) {
- throw InvalidArgumentException::invalidType(
- '$cursor',
- $cursor,
- CursorInterface::class . '&' . Iterator::class,
- );
- }
-
if (isset($initialResumeToken) && ! is_document($initialResumeToken)) {
throw InvalidArgumentException::expectedDocumentType('$initialResumeToken', $initialResumeToken);
}
diff --git a/src/Model/CodecCursor.php b/src/Model/CodecCursor.php
index 642f3c3c1..d7a3776b2 100644
--- a/src/Model/CodecCursor.php
+++ b/src/Model/CodecCursor.php
@@ -17,30 +17,24 @@
namespace MongoDB\Model;
-use Iterator;
use MongoDB\BSON\Document;
use MongoDB\BSON\Int64;
use MongoDB\Codec\DocumentCodec;
-use MongoDB\Driver\Cursor;
-use MongoDB\Driver\CursorId;
use MongoDB\Driver\CursorInterface;
use MongoDB\Driver\Server;
-use ReturnTypeWillChange;
use function assert;
use function iterator_to_array;
use function sprintf;
use function trigger_error;
-use const E_USER_DEPRECATED;
use const E_USER_WARNING;
/**
* @template TValue of object
- * @template-implements CursorInterface
- * @template-implements Iterator
+ * @template-implements CursorInterface
*/
-class CodecCursor implements CursorInterface, Iterator
+class CodecCursor implements CursorInterface
{
private const TYPEMAP = ['root' => 'bson'];
@@ -64,33 +58,16 @@ public function current(): ?object
* @param DocumentCodec $codec
* @return self
*/
- public static function fromCursor(Cursor $cursor, DocumentCodec $codec): self
+ public static function fromCursor(CursorInterface $cursor, DocumentCodec $codec): self
{
$cursor->setTypeMap(self::TYPEMAP);
return new self($cursor, $codec);
}
- /**
- * @return CursorId|Int64
- * @psalm-return ($asInt64 is true ? Int64 : CursorId)
- */
- #[ReturnTypeWillChange]
- public function getId(bool $asInt64 = false)
+ public function getId(): Int64
{
- if (! $asInt64) {
- @trigger_error(
- sprintf(
- 'The method "%s" will no longer return a "%s" instance in the future. Pass "true" as argument to change to the new behavior and receive a "%s" instance instead.',
- __METHOD__,
- CursorId::class,
- Int64::class,
- ),
- E_USER_DEPRECATED,
- );
- }
-
- return $this->cursor->getId($asInt64);
+ return $this->cursor->getId();
}
public function getServer(): Server
@@ -138,7 +115,7 @@ public function valid(): bool
}
/** @param DocumentCodec $codec */
- private function __construct(private Cursor $cursor, private DocumentCodec $codec)
+ private function __construct(private CursorInterface $cursor, private DocumentCodec $codec)
{
}
}
diff --git a/stubs/Driver/Cursor.stub.php b/stubs/Driver/Cursor.stub.php
new file mode 100644
index 000000000..477ece475
--- /dev/null
+++ b/stubs/Driver/Cursor.stub.php
@@ -0,0 +1,41 @@
+
+ */
+final class Cursor implements CursorInterface
+{
+ /**
+ * @return TValue|null
+ * @psalm-ignore-nullable-return
+ */
+ public function current(): array|object|null
+ {
+ }
+
+ public function next(): void
+ {
+ }
+
+ /** @psalm-ignore-nullable-return */
+ public function key(): ?int
+ {
+ }
+
+ public function valid(): bool
+ {
+ }
+
+ public function rewind(): void
+ {
+ }
+
+ /** @return array */
+ public function toArray(): array
+ {
+ }
+}
diff --git a/stubs/Driver/CursorInterface.stub.php b/stubs/Driver/CursorInterface.stub.php
new file mode 100644
index 000000000..2ba7eaa76
--- /dev/null
+++ b/stubs/Driver/CursorInterface.stub.php
@@ -0,0 +1,32 @@
+
+ */
+interface CursorInterface extends Iterator
+{
+ /**
+ * @return TValue|null
+ * @psalm-ignore-nullable-return
+ */
+ public function current(): array|object|null;
+
+ public function getId(): \MongoDB\BSON\Int64;
+
+ public function getServer(): Server;
+
+ public function isDead(): bool;
+
+ /** @psalm-ignore-nullable-return */
+ public function key(): ?int;
+
+ public function setTypeMap(array $typemap): void;
+
+ /** @return array */
+ public function toArray(): array;
+}
diff --git a/tests/Model/CodecCursorFunctionalTest.php b/tests/Model/CodecCursorFunctionalTest.php
index 432d71732..0fb2b35c6 100644
--- a/tests/Model/CodecCursorFunctionalTest.php
+++ b/tests/Model/CodecCursorFunctionalTest.php
@@ -4,16 +4,9 @@
use MongoDB\BSON\Int64;
use MongoDB\Codec\DocumentCodec;
-use MongoDB\Driver\CursorId;
use MongoDB\Model\CodecCursor;
use MongoDB\Tests\FunctionalTestCase;
-use function restore_error_handler;
-use function set_error_handler;
-
-use const E_DEPRECATED;
-use const E_USER_DEPRECATED;
-
class CodecCursorFunctionalTest extends FunctionalTestCase
{
public function setUp(): void
@@ -36,44 +29,6 @@ public function testSetTypeMap(): void
$codecCursor->setTypeMap(['root' => 'array']);
}
- public function testGetIdReturnTypeWithoutArgument(): void
- {
- $collection = self::createTestClient()->selectCollection($this->getDatabaseName(), $this->getCollectionName());
- $cursor = $collection->find();
-
- $codecCursor = CodecCursor::fromCursor($cursor, $this->createMock(DocumentCodec::class));
-
- $deprecations = [];
-
- try {
- $previousErrorHandler = set_error_handler(
- function (...$args) use (&$previousErrorHandler, &$deprecations) {
- $deprecations[] = $args;
-
- return true;
- },
- E_USER_DEPRECATED | E_DEPRECATED,
- );
-
- $cursorId = $codecCursor->getId();
- } finally {
- restore_error_handler();
- }
-
- self::assertInstanceOf(CursorId::class, $cursorId);
-
- // Expect 2 deprecations: 1 from CodecCursor, one from Cursor
- self::assertCount(2, $deprecations);
- self::assertSame(
- 'The method "MongoDB\Model\CodecCursor::getId" will no longer return a "MongoDB\Driver\CursorId" instance in the future. Pass "true" as argument to change to the new behavior and receive a "MongoDB\BSON\Int64" instance instead.',
- $deprecations[0][1],
- );
- self::assertSame(
- 'MongoDB\Driver\Cursor::getId(): The method "MongoDB\Driver\Cursor::getId" will no longer return a "MongoDB\Driver\CursorId" instance in the future. Pass "true" as argument to change to the new behavior and receive a "MongoDB\BSON\Int64" instance instead.',
- $deprecations[1][1],
- );
- }
-
public function testGetIdReturnTypeWithArgument(): void
{
$collection = self::createTestClient()->selectCollection($this->getDatabaseName(), $this->getCollectionName());
@@ -81,24 +36,6 @@ public function testGetIdReturnTypeWithArgument(): void
$codecCursor = CodecCursor::fromCursor($cursor, $this->createMock(DocumentCodec::class));
- $deprecations = [];
-
- try {
- $previousErrorHandler = set_error_handler(
- function (...$args) use (&$previousErrorHandler, &$deprecations) {
- $deprecations[] = $args;
-
- return true;
- },
- E_USER_DEPRECATED | E_DEPRECATED,
- );
-
- $cursorId = $codecCursor->getId(true);
- } finally {
- restore_error_handler();
- }
-
- self::assertInstanceOf(Int64::class, $cursorId);
- self::assertCount(0, $deprecations);
+ self::assertInstanceOf(Int64::class, $codecCursor->getId());
}
}