-
-
Notifications
You must be signed in to change notification settings - Fork 506
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
[2.0] Add type hints #1846
[2.0] Add type hints #1846
Conversation
caciobanu
commented
Aug 6, 2018
Q | A |
---|---|
Type | improvement |
BC Break | yes |
Fixed issues | #1704 |
This is work in progress and only UnitOfWork & DocumentManager are done for now. Some @param & @return docs are invalid so I think that a decision has to be taken which are supported and which not. Take a look at https://github.com/doctrine/mongodb-odm/pull/1846/files#diff-c5b64e39a058b30afece06cc7cd217b7R387 which must support https://github.com/doctrine/mongodb-odm/blob/master/lib/Doctrine/ODM/MongoDB/Query/Builder.php#L109 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Early code review. As a general rule, don't rely on the null
default value to make a type nullable, instead make it explicit.
It may also be beneficial to re-enable these two sniffs in our coding standard to help you with the transition: https://github.com/doctrine/mongodb-odm/blob/215e5e667474b230d41f40fac25a623106bacfed/phpcs.xml.dist#L27,,L28. Mainly, this will apply "easy" type hints when they are already clear-cut due to the @param
typehint, potentially saving you tons of manual work.
Speaking of saving you from work, you can leave out any type hints from classes involved with Proxies: these will be replaced as part of #1813 so there's no point adding type hints now.
Last but not least, if you want to have separate commits for your changes, please make them descriptive. However, as it is now we'll most likely end up squashing this into one large commit.
@@ -524,25 +499,16 @@ public function merge($document) | |||
* @param int $lockVersion | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function lock($document, $lockMode, $lockVersion = null) | |||
public function lock(object $document, int $lockMode, int $lockVersion = null): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?int $lockVersion = null
please.
* @param object|null $document | ||
*/ | ||
public function __construct($msg, $document = null) | ||
public function __construct(string $msg, object $document = null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?object $document = null
*/ | ||
public function findBy(array $criteria, ?array $sort = null, $limit = null, $skip = null) | ||
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$orderBy
and $offset
are incorrect - they are called $sort
and $skip
respectively to reflect the naming in MongoDB: db.collection.find().sort(...).limit(...).skip(...)
.
*/ | ||
public function ensureIndexes($timeout = null) | ||
public function ensureIndexes(int $timeout = null): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?int $timeout = null
*/ | ||
public function updateIndexes($timeout = null) | ||
public function updateIndexes(int $timeout = null): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?int $timeout = null
*/ | ||
public function getDocumentState($document, $assume = null) | ||
public function getDocumentState(object $document, int $assume = null): int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?int $assume = null
* @throws InvalidArgumentException If the entity instance is NEW. | ||
* @throws LockException If the document uses optimistic locking through a | ||
* version attribute and the version check against the | ||
* managed copy fails. | ||
*/ | ||
private function doMerge($document, array &$visited, $prevManagedCopy = null, $assoc = null) | ||
private function doMerge(object $document, array &$visited, object $prevManagedCopy = null, array $assoc = null): object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?object $prevManagedCopy = null, ?array $assoc = null
* @throws LockException | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public function lock($document, $lockMode, $lockVersion = null) | ||
public function lock(object $document, int $lockMode, int $lockVersion = null): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?int $lockVersion = null
*/ | ||
public function clear($documentName = null) | ||
public function clear(string $documentName = null): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?string $documentName = null
* @internal Highly performance-sensitive method. | ||
*/ | ||
public function getOrCreateDocument($className, $data, &$hints = [], $document = null) | ||
public function getOrCreateDocument(string $className, array $data, array &$hints = [], object $document = null): object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?object $document = null
Thanks for the feedback! I'll do a rebase when I'll finish. I'm doing this step by step to be easier to fix failing tests or to update type hints. And yes, I know about Doctrine\Common\Proxy being replaced with ocramius/proxy-manager so I will ignore involved classes. |
@alcaeus I'm not sure about the code in lib/Doctrine/ODM/MongoDB/Aggregation. Is it worth it to add type hints there ? For some classes I couldn't find any usages. |
Most of the arguments to the methods in aggregation pipeline stages accept multiple arguments: a scalar value, an array containing a MongoDB expression or an aggregation Do you have any specific issues with aggregation classes? |
@alcaeus Can you take a look at \Doctrine\ODM\MongoDB\Aggregation\Stage\GraphLookup\Match::getExpression ? I'm not sure that the method body is correct because \Doctrine\ODM\MongoDB\Aggregation\Stage::getExpression says that the return type should be an array. |
I think I've understood why the method body is like that: search for restrictSearchWithMatch https://docs.mongodb.com/manual/reference/operator/aggregation/graphLookup/ |
@alcaeus finished adding as much type hints as possible. There are some tests failing but I have no ideea how to fix them. |
Regarding As for tests I can take a look at the two failing tests and why they fail. Step-debugging should prove helpful here to see where they go wrong. Once we've done that and fixed issues found by our static analysers (phpcs and PHPStan) I'll give this another review. |
I've made a minor change to Doctrine\ODM\MongoDB\Aggregation\Stage\GraphLookup\Match::getExpression so we can have only 1 return type: array. Take a look at https://github.com/doctrine/mongodb-odm/pull/1846/files#diff-149e2cae007283dbcfb76c37c91fe524R27 and https://github.com/doctrine/mongodb-odm/pull/1846/files#diff-40007aeae56972528d22a8a3f15acf17R175 |
@alcaeus I've managed to track down the issue with the failing tests. As you can see in commit 6bdd9c6 when I changed the typehint for dm->clear() to string I couldn't provide the $user object as before so I provided the class but that made the uow to clear the objects used later in the ->contains checks. Providing an invalid string value mimics the behavior before the type hints where added. |
@alcaeus this is ready for review 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mighty impressive PR, thank you very much. I found some minor issues that need fixing. Also, as mentioned above, I believe it would be worth removing the exclusions in phpcs.xml I linked above to see if there are any other places where we might add some typehints.
{ | ||
$restrictSearchWithMatch = $this->restrictSearchWithMatch->getExpression() ?: (object) []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
{ | ||
return $this->document; | ||
} | ||
|
||
public static function lockFailed($document) | ||
public static function lockFailed($document): self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this have an ?object
type for $document
?
* @return ObjectRepository|GridFSRepository | ||
*/ | ||
protected function createRepository(DocumentManager $documentManager, $documentName) | ||
protected function createRepository(DocumentManager $documentManager, string $documentName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also have a common ObjectRepository
return type.
*/ | ||
public function containsId($id, $rootClassName) | ||
public function containsId(string $id, string $rootClassName): bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may have been documented wrongly in the docblock - most other methods don't specify a type for the ID.
*/ | ||
public function getClassNameForAssociation(array $mapping, $data) | ||
public function getClassNameForAssociation(array $mapping, $data): string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?array $data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like ?array is not enough. object is needed also.
@@ -61,7 +61,7 @@ public function testRemoveEmbedMany() | |||
$user->profileMany->removeElement($profile1); | |||
|
|||
$this->dm->flush(); | |||
$this->dm->clear($user); | |||
$this->dm->clear('invalid'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this fixes the test, but if the clear
didn't do anything so we might as well drop it instead of passing invalid stuff
Updated after review & enabled the CS rules you mentioned above. |
Yaaay, another few k diff PR :D Thanks a lot @caciobanu for your work on this, I'll review tomorrow while in the office :) |
The activated CS rules run on lib and tests. The output is huge. Should I run phpcbf and then go from there ? |
Unfortunately phpcs adds invalid parameter type hints on inherited methods from vendor packages, which lack type hints. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was afraid that phpcs might find more than it should - we'll have to leave the sniffs excluded until we're completely done across the board, and even then might have to exclude some code pieces. Either way, I don't think it's feasible fixing those errors now - at least not at that scale.
My suggestion would be to bring this PR to a close, then focus on interfaces and abstract classes we're introducing here that don't have outside dependencies. Our first focus should be to get those cleaned up. In a second step, we should take care of other classes we're introducing, along with making them final unless we think they should be extended (which most likely, we don't). At the same time, we should also start the process of starting upstream updates in doctrine/persistence and so on, but that should wait until we got rid of doctrine/common.
*/ | ||
public function granularity($granularity) | ||
public function granularity(string $granularity): \Doctrine\ODM\MongoDB\Aggregation\Stage\BucketAuto |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be shortened as with the method above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Will do.
Disabled the CS rules for type hinting. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for late and long review, but I really wanted to read this through :)
*/ | ||
public function limit($limit) | ||
public function limit(int $limit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing return type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't added it because of \Doctrine\ODM\MongoDB\Aggregation\Stage\GeoNear::limit which overrides it and has different returned type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add back in the comment @return Stage\Limit
* @return $this | ||
*/ | ||
public function limit($limit) | ||
public function limit(int $limit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing return type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the comment above.
* @return $this | ||
*/ | ||
public function maxDistance($maxDistance) | ||
public function maxDistance(float $maxDistance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I add to this method self I cannot add type hint to \Doctrine\ODM\MongoDB\Aggregation\Stage\Match::maxDistance. If I add to \Doctrine\ODM\MongoDB\Aggregation\Stage\Match::maxDistance then the method above has to return \Doctrine\ODM\MongoDB\Aggregation\Stage\Match
* @return $this | ||
* | ||
*/ | ||
public function minDistance($minDistance) | ||
public function minDistance(float $minDistance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same as above applies here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'll need to say it at least once more, but sorry for the noise then :)
{ | ||
return $this->dm->getUnitOfWork()->getDocumentPersister($class->name); | ||
} | ||
|
||
private function getReferencedFieldName($fieldName, array $mapping) | ||
private function getReferencedFieldName(string $fieldName, array $mapping): ?string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is return type nullable? It seems like it's either string
or an exception is thrown
* @param array|string $filter | ||
* @return array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for @return
@@ -39,10 +37,7 @@ public function __construct(\ArrayIterator $metadata, $filter) | |||
parent::__construct($metadata); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't comment on actual place, but can you set $this->_filter
to be string[]
and hint in ctor that $filter is string|string[]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -273,11 +273,8 @@ public function __construct(DocumentManager $dm, EventManager $evm, HydratorFact | |||
|
|||
/** | |||
* Factory for returning new PersistenceBuilder instances used for preparing data into | |||
* queries for insert persistence. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be removed ;)
@@ -2478,11 +2329,8 @@ public function getVisitedCollections($document) | |||
/** | |||
* INTERNAL: | |||
* Gets PersistentCollections that are scheduled to update and related to $document | |||
* | |||
* @param object $document | |||
* @return array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you keep this with PersistentCollectionInterface[]
?
*/ | ||
public function registerManaged($document, $id, $data) | ||
public function registerManaged(object $document, $id, $data): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add array
for $data
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually even if something is still off a bit, let's get this merged once Travis is green!
Before merging I can do a rebase to get rid of all those horrid commit messages. |
Yeah, go ahead and give this a rebase - once the build is stable again I'd like to get this merged 🎉 |
c88da82
to
724c044
Compare
Done. |
Thanks @caciobanu! 🎖 |
Glad to help! |