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

Allow usage with PSR-7 v2 #136

Merged
merged 14 commits into from
May 1, 2023

Conversation

weierophinney
Copy link
Member

@weierophinney weierophinney commented Apr 5, 2023

Q A
Documentation no
Bugfix no
BC Break yes
New Feature yes
RFC no
QA yes

Description

This patch adapts Diactoros to work with either PSR-7 v1.1 or v2.0 by explicitly adding the parameter type hints defined in PSR-7 v2.0, as well as void return type declarations where not previously declared.

This patch depends on the following upstream changes:

This patch should be applied to an upcoming 3.0.x branch, for release as 3.0, due to the following BC breaks:

  • Addition of explicit parameter type declarations (where known) to all PSR-7 implementation signatures. This change will break any extensions of these classes, as the signatures have changed in a way that does not conform to covariance rules for return types. Specifically, any method that was updated to return void in the PSR-7 spec that we had not marked in our own implementation with a void return declaration leads to the BC break, as updating our implementation means extensions that do not declare it will now cause a fatal error.

Tasks

The following are required before removing this from draft status:

composer.json Outdated Show resolved Hide resolved
composer.json Outdated Show resolved Hide resolved
composer.json Outdated Show resolved Hide resolved
psalm.xml.dist Outdated Show resolved Hide resolved
src/CallbackStream.php Show resolved Hide resolved
@weierophinney weierophinney changed the base branch from 2.25.x to 2.26.x April 6, 2023 19:09
@TimWolla
Copy link
Contributor

TimWolla commented Apr 6, 2023

This change will break any extensions of these classes, as the signatures have changed in a way that does not conform to contravariance rules for parameters.

I do not believe this description is accurate. A deriving class may leave out parameter types of a parent class (“widen the type”), because everything that may be passed to the parent class may still be passed to the deriving class: https://3v4l.org/gfWBN

However adding parameter types may break consumers that rely on passing an invalid type. However to my understanding, Diactoros already included checks to validate the type.

So, I believe this is safe for a minor, unless I'm missing something?

Many tests become redundant with proper types present.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
@weierophinney
Copy link
Member Author

@TimWolla

So, I believe this is safe for a minor, unless I'm missing something?

You were right about the contravariance versus covariance bit; I had that part wrong in the description and have since corrected it.

The problem is actually with the return type hints: when we were defining return type hints in this implementation, we missed a few cases that later became void in the PSR-7 v2 spec. Going from implied mixed to void is the BC break. If an extension of a method now defined to return void returns something or omits the return type declaration, PHP will raise a fatal error.

psalm.xml.dist.orig Outdated Show resolved Hide resolved
@boesing
Copy link
Member

boesing commented Apr 19, 2023

I wonder if we should pin php-http integration tests to specific versions anyway. Since they can change upstream, it might lead to failing checks in PRs which are unrelated to those changes. Having renovate bumping these commits could help, no?

@Xerkus
Copy link
Member

Xerkus commented Apr 26, 2023

Having renovate bumping these commits could help, no?

That would only affect latest branch.
Integration tests could be updated to cover newly discovered cross-compatibility issue and we would want CI fail for older branches too, imo.

@boesing
Copy link
Member

boesing commented Apr 26, 2023

That would only affect latest branch.

More than enough for PRs.

Integration tests could be updated to cover newly discovered cross-compatibility issue and we would want CI fail for older branches too, imo.

Having scheduled build for that where we explictly use composer require integration-tests:dev-master should be used for discovering these kinds of issues.

@Xerkus
Copy link
Member

Xerkus commented Apr 29, 2023

Both dependencies got releases. 1.0.2 and 1.3.0 respectively

…ests

- Updates to version 1.0.2 of the PSR-17 interfaces, which allow usage with PSR-7 v2
- Updates to version 1.3.0 of the psr7-integration-tests, which allow usage with PSR-7 1.1 and 2.0.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
Due to updating to use PSR-7 v2, we can remove a number of conditionals that did type-checking, and also update constructors to use union types to fully type the API exposed.
Doing so removes the need for some unit tests, as type errors will now be guaranteed by the runtime.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
- Updates the ref for the PSR-7 integration tests with a version known to work.
- Fixes the signature of `CallbackStream::seek` to add the `void` return declaration.
- Applies CS rules.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
- Update to stable http-factory with support for PSR-7 v2.
- Updates to add settings that will be required with Psalm 6.
- Removes some unnecessary type checks, as parameter type declarations are now present.
- Updates tests to remove assertions about types when they are known.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
Unused import statements

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
@weierophinney weierophinney marked this pull request as ready for review May 1, 2023 13:25
@weierophinney weierophinney changed the base branch from 2.26.x to 3.0.x May 1, 2023 13:27
@weierophinney
Copy link
Member Author

I've now created the 3.0.x branch, and updated this patch to be against that branch. Additionally, both psr/http-factory and php-http/psr7-integration-tests have released stable versions that support PSR-7 1.1 and 2.0, allowing me to rebase my patch to reference the stable branches.

Ready for final review and release! Once done, I'll turn my efforts to laminas/laminas-stratigility, and then the various Mezzio components.

test/MessageTraitTest.php Outdated Show resolved Hide resolved
test/ResponseTest.php Outdated Show resolved Hide resolved
test/UriTest.php Outdated Show resolved Hide resolved
test/ResponseTest.php Outdated Show resolved Hide resolved
test/ResponseTest.php Outdated Show resolved Hide resolved
Copy link
Member

@boesing boesing left a comment

Choose a reason for hiding this comment

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

LGTM

We still need to test _string_ versions that resolve to unsupported protocol versions.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
Per @Xerkus

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
Per @Xerkus

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
Copy link
Member

@Ocramius Ocramius left a comment

Choose a reason for hiding this comment

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

🚢

Thanks @weierophinney!

Copy link
Member

@Xerkus Xerkus left a comment

Choose a reason for hiding this comment

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

public function withRequestTarget($requestTarget): RequestInterface

Missing parent type declaration.


Some tangentially related comments:

public function __construct(
$streamOrFile,
private int $size,

Interface defines size as nullable. This should probably be changed to nullable too. If so this will need to be backported to 2.x

private function validateProtocolVersion($version): void

MessageTrait::validateProtocolVersion() could have argument type defined and is_string check dropped to match withProtocolVersion().

public function getAttribute(string $attribute, $default = null)

This uses parameter name $attribute and interface uses $name. Should be changed for consistency. Same for withAttribute()

public function createStreamFromFile(string $file, string $mode = 'r'): StreamInterface

Interface uses $filename

@weierophinney
Copy link
Member Author

Missing parent type declaration.

Thanks - updating that now.

@weierophinney
Copy link
Member Author

Interface defines size as nullable. This should probably be changed to nullable too. If so this will need to be backported to 2.x

While the size can be nullable, we're saying in this particular implementation that it must be an integer. Since this narrows what we return from getSize(), it's still valid and fulfills the spec. I see no reason to change this currently.

…Target()`

should be string!

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
…rait::validateProtocolVersion`

We know it's a string internally, so we can mark it one here, and remove a redundant conditional.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
@Xerkus
Copy link
Member

Xerkus commented May 1, 2023

While the size can be nullable, we're saying in this particular implementation that it must be an integer.

This somewhat conflicts with the argument of UriFactory as using null will lead to type error

public function createUploadedFile(
StreamInterface $stream,
?int $size = null,
int $error = UPLOAD_ERR_OK,
?string $clientFilename = null,
?string $clientMediaType = null
): UploadedFileInterface {
if ($size === null) {
$size = $stream->getSize();
}
return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType);
}

@weierophinney
Copy link
Member Author

public function getAttribute(string $attribute, $default = null)

This uses parameter name $attribute and interface uses $name. Should be changed for consistency. Same for withAttribute()

public function createStreamFromFile(string $file, string $mode = 'r'): StreamInterface

Interface uses $filename

I think these should be done with the 2.x series, and then merged up.

@weierophinney
Copy link
Member Author

While the size can be nullable, we're saying in this particular implementation that it must be an integer.

This somewhat conflicts with the argument of UriFactory as using null will lead to type error

Alright, that argument I can get behind. I'll make it nullable, but not have a default value.

Since the `UploadedFileFactoryInterface` allows nullable size, not allowing it here could lead to an error condition.

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
@Xerkus
Copy link
Member

Xerkus commented May 1, 2023

Alright, that argument I can get behind. I'll make it nullable, but not have a default value.

Will you make PR against 2.x or should I?

@weierophinney
Copy link
Member Author

@Xerkus

I've pushed changes for each of the following issues you flagged:

  • Added the missing string parameter type declaration to RequestTrait::withRequestTarget()
  • Added a string parameter type declaration to MessageTrait::validateProtocolVersion()'s $version argument, and removed the unneeded conditional that checked for a string in that method.
  • Made the $size argument/property in UploadedFileFactoryInterface nullable.

I've been thinking about the parameter name changes, and it DOES NOT make sense to do them on the 2.x branch, as, with named arguments in PHP 8, this would be a BC break (name changes). While it could be considered a bugfix, it would potentially break code for users. So let's do it here; I'll push those shortly.

- `ServerRequest` `getAttribute` and `withAttribute` methods: rename `$attribute` to `$name`.
- `StreamFactory::createStreamFromFile()`: rename `$file` to `$filename`

Signed-off-by: Matthew Weier O'Phinney <[email protected]>
@Xerkus Xerkus merged commit 5f68a73 into laminas:3.0.x May 1, 2023
@Xerkus
Copy link
Member

Xerkus commented May 1, 2023

@weierophinney thank you!

@weierophinney weierophinney deleted the feature/psr-7-type-hints branch May 1, 2023 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants