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

Drop PHP 7, add PHP 8.2 Support #39

Merged
merged 7 commits into from
Jul 10, 2023

Conversation

rogervila
Copy link
Contributor

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

Description

Drop PHP 7, add PHP 8.2 Support

Signed-off-by: Roger Vilà <rogervila@me.com>
Signed-off-by: Roger Vilà <rogervila@me.com>
@rogervila
Copy link
Contributor Author

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.

.gitignore Outdated Show resolved Hide resolved
Signed-off-by: Roger Vilà <rogervila@me.com>
Copy link
Member

@gsteel gsteel left a 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 👍

src/Collection.php Outdated Show resolved Hide resolved
src/EntityHydratorManager.php Outdated Show resolved Hide resolved
src/Link/Link.php Outdated Show resolved Hide resolved
src/Link/Link.php Outdated Show resolved Hide resolved
src/Metadata/Metadata.php Outdated Show resolved Hide resolved
src/View/HalJsonStrategy.php Outdated Show resolved Hide resolved
src/View/HalJsonStrategy.php Outdated Show resolved Hide resolved
test/Plugin/HalTest.php Outdated Show resolved Hide resolved
test/Plugin/TestAsset/JsonSerializableEntity.php Outdated Show resolved Hide resolved
test/TestAsset/JsonSerializable.php Outdated Show resolved Hide resolved
@froschdesign froschdesign removed their request for review January 11, 2023 12:20
@weierophinney
Copy link
Contributor

I'll review after you've incorporated the feedback from @gsteel .

Thanks, @rogervila !

Signed-off-by: Roger Vilà <rogervila@me.com>
@rogervila rogervila requested a review from gsteel January 12, 2023 10:46
@rogervila
Copy link
Contributor Author

@weierophinney @gsteel I have applied the required changes. Let me know if there is something else to change.

Copy link
Member

@gsteel gsteel left a 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{
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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
Comment on lines 24 to 25
<exclude-pattern>src/Plugin/Hal.php</exclude-pattern>
<exclude-pattern>test/ResourceFactoryTest.php</exclude-pattern>
Copy link
Member

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 (?)

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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.

@rogervila rogervila requested a review from gsteel January 12, 2023 14:48
Copy link
Contributor

@weierophinney weierophinney left a 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.

Comment on lines 19 to 22
/** @var HelperPluginManager $helpers */
$helpers = $container->get('ViewHelperManager');
/** @var ApiProblemRenderer $apiProblemRenderer */
$apiProblemRenderer = $container->get(ApiProblemRenderer::class);
Copy link
Contributor

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/Factory/HalJsonStrategyFactory.php Show resolved Hide resolved
Comment on lines 82 to 83
$relation = $spec['rel'];
$link = new static($relation);
Copy link
Contributor

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?

Comment on lines 79 to 81
/** @var Paginator $collection */
$collection = $halCollection->getCollection();
$page = $collection->count();
Copy link
Contributor

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)
        }

Copy link
Contributor Author

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

Comment on lines 100 to 102
/** @var Paginator $collection */
$collection = $halCollection->getCollection();
$pageCount = $collection->count();
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as previous.

Comment on lines 177 to 178
$options = $this->map[$class];
$this->map[$class] = new Metadata($class, $options, $this->getHydratorManager());
Copy link
Contributor

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.

Comment on lines 697 to 699
/**
* @var mixed $value
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/**
* @var mixed $value
*/
/** @var mixed $value */

@@ -155,15 +156,16 @@ public function getController()
*
* @return self
*/
public function setEventManager(EventManagerInterface $events)
public function setEventManager(EventManagerInterface $eventManager)
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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.

*/
$callback = function ($r) {
$callback = function ($r): bool {
Copy link
Contributor

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 {

src/ResourceFactory.php Outdated Show resolved Hide resolved
Signed-off-by: Roger Vilà <rogervila@me.com>
@rogervila rogervila requested review from weierophinney and gsteel and removed request for gsteel and weierophinney January 12, 2023 17:21
@rogervila
Copy link
Contributor Author

Hi, please check this comment so I can fix the CI

Signed-off-by: Roger Vilà <rogervila@me.com>
@rogervila
Copy link
Contributor Author

Hi @weierophinney, the PR is ready to be reviewed. Let me know if any additional change is needed.

Copy link
Contributor

@weierophinney weierophinney left a 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)

psalm.xml.dist Outdated Show resolved Hide resolved
src/Factory/HalConfigFactory.php Outdated Show resolved Hide resolved
src/Factory/HalControllerPluginFactory.php Outdated Show resolved Hide resolved
src/Factory/HalJsonRendererFactory.php Outdated Show resolved Hide resolved
src/Factory/HalJsonStrategyFactory.php Outdated Show resolved Hide resolved
src/Factory/HalViewHelperFactory.php Outdated Show resolved Hide resolved
src/Link/PaginationInjector.php Show resolved Hide resolved
Signed-off-by: Roger Vilà <rogervila@me.com>
@rogervila
Copy link
Contributor Author

rogervila commented Jan 26, 2023

Hello @weierophinney, @gsteel, @froschdesign,

I applied the latest required changes. Let me know if there is something else to change.

@rogervila rogervila requested review from weierophinney and gsteel and removed request for weierophinney January 26, 2023 11:26
@jonkerw85
Copy link

What is the status? As far as I can see, this merge request is blocking the following projects from upgrading to 8.2.

@rchrdkn
Copy link

rchrdkn commented Jun 23, 2023

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!

@rogervila
Copy link
Contributor Author

Hi @rchrdkn, the PR is waiting to be approved by the core team.

Meanwhile, I suggest using this fork, which provides PHP 8.2 support.

@weierophinney weierophinney added this to the 1.10.0 milestone Jul 10, 2023
@weierophinney weierophinney added the Enhancement New feature or request label Jul 10, 2023
@weierophinney weierophinney merged commit 3cc89f2 into laminas-api-tools:1.10.x Jul 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants