-
-
Notifications
You must be signed in to change notification settings - Fork 13
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
Drop PHP 7, add PHP 8.2 Support #39
Conversation
Signed-off-by: Roger Vilà <rogervila@me.com>
Signed-off-by: Roger Vilà <rogervila@me.com>
Hello @weierophinney @Ocramius, This PR is part of the Laminas API Tools PHP 8.2 support that I am working on. Most of the modifications are Psalm and PHPCS error fixes. Let me know if I should apply any other changes. Thank you. |
Signed-off-by: Roger Vilà <rogervila@me.com>
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.
Thanks for the huge effort @rogervila - This is just a general skim - I don't have a deep knowledge of this project so I won't be able to ultimately approve this patch without review from other team members 👍
I'll review after you've incorporated the feedback from @gsteel . Thanks, @rogervila ! |
Signed-off-by: Roger Vilà <rogervila@me.com>
@weierophinney @gsteel I have applied the required changes. Let me know if there is something else to change. |
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.
Thanks for incorporating the feedback @rogervila, a couple of notes, but I'll hand over to @weierophinney now :)
* @var string|array $route Optional. | ||
* @var string $url {@deprecated since 1.5.0; use 'href' instead} Optional. | ||
* } | ||
* @psalm-param 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.
FYI, you can add a psalm type to the class-level doc block such as:
/**
* @psalm-type LinkArraySpec = array{
* rel: string|whatever
* other: list<whatever>
* }
*/
And then use that type for your parameter and return docs: @return LinkArraySpec
instead of copying and pasting the entire spec around.
In other classes, the type can be imported with @psalm-import-type LinkArraySpec from ImportedClassName
on the class-level doc block.
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.
Hi @gsteel, I have tried to extract it to a type, but then psalm raises some MixedArgumentTypeCoercion
errors due to the fact that the initial status of $links
property at src/Metadata/Metadata.php:88
is initialized as an empty array (read as array<empty,empty>
by psalm)
Any change on the initial property status would be considered a BC, so I suggest keeping the duplicated $spec
Psalm definition as added on the latest commit.
What do you think?
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.
You can make each of the keys optional:
/**
* @psalm-type LinkArraySpec = array{
* rel?: string|whatever,
* other?: list<whatever>
* }
*/
Doing so gives you both the correct shape AND allows for empty arrays.
phpcs.xml.dist
Outdated
<exclude-pattern>src/Plugin/Hal.php</exclude-pattern> | ||
<exclude-pattern>test/ResourceFactoryTest.php</exclude-pattern> |
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.
These exclusions shouldn't be necessary - The factories all reference Interop\ContainerInterface
which is probably class_aliased
causing the false negative for phpcs, so that's fine, but if an CS error is showing up for these two, it's likely an actual error (?)
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.
Thank you @gsteel
By removing them, I get the following error:
Expected class name interop\container\containerinterface; found Interop\Container\ContainerInterface
Expected class name interop\container\exception\containerexception; found Interop\Container\Exception\ContainerException
I am not sure why PHPCS requires the class to be lowercase. Is there any other solution instead of ignoring those files?
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 am not sure why PHPCS requires the class to be lowercase.
This is an error and the class name should be reverted.
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 @froschdesign, I did not set the class name to lowercase. Instead, I ignored the error on the PHPCS config file.
So, if you agree, I will keep the ignored errors on the PHPCS config file since we do not want to set those classes to lowercase. Is that ok @froschdesign, @gsteel?
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 - specifically I was talking about the suppressions for Laminas class names - theses should not be suppressed. The class names from Interop should be correctly cased in the code i.e. Interop\Container\ContainerInterface
and then the invalid error surfaced by PHPCS should be suppressed. The error itself stems from class_alias
stuff from laminas-servicemanager
and a possible bug in the related sniff - In theory, if you bump laminas-servicemanager
to the correct minimum version (^3.11, but preferably ^3.18) where it replaces interop, you can drop Container Interop from deps completely, replace everything with Psr\Container and remove all the suppressions in phpcs.xml - but it's probably best to keep that for another patch as I'm not sure how well that will play with other deps in this project.
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.
Thank you. I will apply this change on the next commit.
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.
Looking good!
Themes during my review:
- We shouldn't be excluding entire classes from CS checks. Use
// phpcs:disable <check name>
/// phpcs:enable <check name>
blocks instead (or disable specific rules at the file level). - In factories, prefer assertions of returned types pulled from the container to using
@var
annotations.
I've also noted a place where we're using call_user_func_array
and proposed an alternative implementation.
/** @var HelperPluginManager $helpers */ | ||
$helpers = $container->get('ViewHelperManager'); | ||
/** @var ApiProblemRenderer $apiProblemRenderer */ | ||
$apiProblemRenderer = $container->get(ApiProblemRenderer::class); |
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.
Since this is a factory, it might be better for us to perform assertions on the returned types instead of using annotations:
$helpers = $container->get('ViewHelperManager');
assert($helpers instanceof ContainerInterface);
$apiProblemRenderer = $container->get(ApiProblemRenderer::class);
assert($apiProblemRenderer instanceof ApiProblemRenderer);
src/Link/Link.php
Outdated
$relation = $spec['rel']; | ||
$link = new static($relation); |
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 the array shape is defined for $spec
, do we need the intermediary variable here and throughout this method?
src/Link/PaginationInjector.php
Outdated
/** @var Paginator $collection */ | ||
$collection = $halCollection->getCollection(); | ||
$page = $collection->count(); |
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.
We shouldn't assert that this is a Paginator
instance here. getCollection()
is defined as returning an array, Traversable, or Paginator. As such, we need to check for Countable or array, and anything else we cannot know how to count.
$collection = $halCollection->getCollection();
if ($collection instanceof Countable) {
$page = $collection->count();
} elseif (is_array($collection)) {
$page = count($page);
} else {
// either throw an exception here (uncountable collection) or use a default for $page (e.g. 1)
}
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 keep 1 as default to avoid BC
src/Link/PaginationInjector.php
Outdated
/** @var Paginator $collection */ | ||
$collection = $halCollection->getCollection(); | ||
$pageCount = $collection->count(); |
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 comment as previous.
src/Metadata/MetadataMap.php
Outdated
$options = $this->map[$class]; | ||
$this->map[$class] = new Metadata($class, $options, $this->getHydratorManager()); |
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.
Was Psalm complaining about this? I'm not sure why we would need to have the intermediary variable here.
src/Plugin/Hal.php
Outdated
/** | ||
* @var mixed $value | ||
*/ |
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.
/** | |
* @var mixed $value | |
*/ | |
/** @var mixed $value */ |
src/Plugin/Hal.php
Outdated
@@ -155,15 +156,16 @@ public function getController() | |||
* | |||
* @return self | |||
*/ | |||
public function setEventManager(EventManagerInterface $events) | |||
public function setEventManager(EventManagerInterface $eventManager) |
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.
Is the change in variable name really necessary here? Elsewhere in the class, we still use $events
.
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.
It was a PHPStorm complain. Reverting.
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.
Is the change in variable name really necessary here? Elsewhere in the class, we still use
$events
.
Hi @weierophinney, Psalm is failing if I keep the $events
variable name:
Error: src/Plugin/Hal.php:159:59: ParamNameMismatch: Argument 1 of Laminas\ApiTools\Hal\Plugin\Hal::setEventManager has wrong name $events, expecting $eventManager as defined by Laminas\EventManager\EventManagerAwareInterface::setEventManager (see https://psalm.dev/230)
Should I ignore or fix the issue?
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.
Ah, okay, that makes sense - because with PHP 8, and the introduction of named arguments, a deviation in argument name when implementing an interface would be considered a potential contractual change.
Go ahead and change it, then - and note in the commit the reason why.
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 problem comes from laminas/laminas-eventmanager
On the EventManagerAwareInterface
, the parameter is called $eventManager
while on EventManagerAwareTrait
is called $events
This triggers a Psalm error no matter which variable name I use, so I have ignored it. I have also opened an Issue on the library to fix it.
I think the PR is ready to be merged. Please, @weierophinney, let me know if there is anything else to change.
src/Plugin/Hal.php
Outdated
*/ | ||
$callback = function ($r) { | ||
$callback = function ($r): 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.
Since we're setting the minimum PHP version to 8.0, I'd get rid of the annotation and make this simply:
$callback = function (mixed $r): bool {
Signed-off-by: Roger Vilà <rogervila@me.com>
Hi, please check this comment so I can fix the CI |
Signed-off-by: Roger Vilà <rogervila@me.com>
Hi @weierophinney, the PR is ready to be reviewed. Let me know if any additional change is needed. |
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.
Themes of things I saw during this round of reviews:
- Psalm suppressions were put in the
psalm.xml.dist
file instead of as annotations in files. They should be as close to the code as possible, otherwise we run the risk of introducing additional occurrences later that are then unflagged. - You can use
phpcs:ignore
to ignore a CS rule on a single line. - There's inconsistent refactoring of factories. Some are using assertions to test values returned from the container, and others are using annotations to flag to Psalm what the value is. Go with one or the other; my recommendation is using assertions, as Psalm understand them, and they give additional runtime safety.
- Extract the link array spec as a Psalm type template, and use it wherever needed, instead of recreating it. Since it has some complexity to it, it would be easier to re-use than to risk having one or more go out of date.
- Extract the count function (example provided for you)
Signed-off-by: Roger Vilà <rogervila@me.com>
Hello @weierophinney, @gsteel, @froschdesign, I applied the latest required changes. Let me know if there is something else to change. |
What is the status? As far as I can see, this merge request is blocking the following projects from upgrading to 8.2. |
Hi @rogervila, @weierophinney, @gsteel, @froschdesign What's the latest on this? It would be great to get 8.2 support for this and those blocked by it! |
Description
Drop PHP 7, add PHP 8.2 Support