Skip to content

Cleanup phpstan baseline issues#308

Open
tuj wants to merge 25 commits into
developfrom
feature/phpstan-cleanup-baseline
Open

Cleanup phpstan baseline issues#308
tuj wants to merge 25 commits into
developfrom
feature/phpstan-cleanup-baseline

Conversation

@tuj

@tuj tuj commented May 17, 2026

Copy link
Copy Markdown
Contributor

Link to ticket

https://leantime.itkdev.dk/TimeTable/#/tickets/showTicket/7273

Description

Cleanup phpstan baseline issues.

  • PHPStan baseline: 530 → 0.
  • Migration Version20260517131038: 18 columns made nullable on synced entities
    (issue, project, version, worklog) plus 3 DateTime fields, to match property types.
  • Migration Version20260517151632: 11 NOT NULL ManyToOne FKs relaxed to NULL;
    application-layer #[Assert\NotNull] / form validators still enforce required-ness.
  • Replaced ?T $prop = null with non-null defaults on 25 entity properties to satisfy
    NOT NULL columns; Worker/WorkerGroup __toString() switched from ?? to ?:.
  • ForecastReportService rendered empty epic tags — called non-existent Epic::getName();
    now uses Epic::getTitle().
  • SubscriptionHandlerService::getVersion() looked up Version by non-existent
    versionId field; now uses find($versionId).
  • DataProviderService::setTimeSpentSeconds() silently lost precision passing float to an
    int setter; explicit (int) cast added.
  • Report services (ForecastReportService, BillableUnbilledHoursReportService,
    InvoicingRateReportService) now skip worklogs with null project/issue instead of crashing.
  • SubscriptionController::check() returns HTTP 400 on null User::getEmail();
    User::getUserIdentifier() throws on empty email (Symfony requires non-empty-string).
  • LeantimeApiService switched from json_decode($json, null) to json_decode($json, true);
    all $data->property accesses converted to array access. Wire shape unchanged.
  • Removed dead code: readonly string $id on 3 report-data models, unreachable break; after
    throw, null check on Row iterator, unused $paginator arg in SubscriptionRepository.
  • Fixed Epic::getIssues() PHPDoc typo (Collection<int, Epic>Collection<int, Issue>).

Checklist

  • My code is covered by test cases.
  • My code passes our test (all our tests).
  • My code passes our static analysis suite.
  • My code passes our continuous integration process.

@tuj tuj self-assigned this May 17, 2026
@tuj tuj added the enhancement New feature or request label May 17, 2026
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 31.48148% with 111 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (feature/psalm-to-phpstan@b3b0d9f). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/Service/InvoicingRateReportService.php 0.00% 16 Missing ⚠️
src/Service/ForecastReportService.php 0.00% 14 Missing ⚠️
src/Service/LeantimeApiService.php 76.78% 13 Missing ⚠️
src/Controller/SubscriptionController.php 0.00% 9 Missing ⚠️
src/Controller/ProjectBillingController.php 0.00% 8 Missing ⚠️
src/Service/BillableUnbilledHoursReportService.php 0.00% 8 Missing ⚠️
src/Controller/InvoiceController.php 0.00% 7 Missing ⚠️
src/Controller/ManagementReportController.php 0.00% 7 Missing ⚠️
src/Service/HourReportService.php 0.00% 4 Missing ⚠️
src/DataFixtures/AppFixtures.php 0.00% 3 Missing ⚠️
... and 13 more
Additional details and impacted files
@@                     Coverage Diff                     @@
##             feature/psalm-to-phpstan     #308   +/-   ##
===========================================================
  Coverage                            ?   17.44%           
  Complexity                          ?     1714           
===========================================================
  Files                               ?      202           
  Lines                               ?     7155           
  Branches                            ?        0           
===========================================================
  Hits                                ?     1248           
  Misses                              ?     5907           
  Partials                            ?        0           
Flag Coverage Δ
17.44% <31.48%> (?)
unittests 17.44% <31.48%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Base automatically changed from feature/psalm-to-phpstan to develop May 20, 2026 08:01
@tuj tuj marked this pull request as ready for review June 1, 2026 19:08
@tuj tuj requested a review from jeppekroghitk June 2, 2026 05:00

@jeppekroghitk jeppekroghitk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A few comments to consider before merging. Nice job.

{
public function getDescription(): string
{
return 'Make columns nullable on synced entities (issue/project/version/worklog) and on app-managed DateTime fields (project_billing period_start/end, service_agreement valid_from) to match PHP property types.';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't like the idea that Claude edited this file. Description is not filled out when doctrine generates it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude only wrote the descriptions.

{
public function getDescription(): string
{
return 'Make ManyToOne foreign keys nullable on entities whose properties are typed nullable. Aligns DB schema with PHP property types; application/validation layer still enforces required-ness on app-managed entities.';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude only wrote the descriptions.

Comment on lines -63 to -65
if (null === $row) {
continue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you sure that the calls on $row after this will not fail hard, if $row is null?

For example at $row->getNumCells().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In essence yes:

  • RowIteratorInterface::current(): ?Row — the interface contract allows null (vendor/openspout/openspout/src/Reader/RowIteratorInterface.php:15).
  • CSV RowIterator implementation only returns a Row once valid() is true, and PHP's foreach checks valid() before each current() call — so in practice $row will never be null during normal
    iteration (vendor/openspout/openspout/src/Reader/CSV/RowIterator.php:99-102, :73-76).

Comment thread CHANGELOG.md
Comment on lines +11 to +35
* [PR-308](https://github.com/itk-dev/economics/pull/308)
* PHPStan baseline: 530 → 0 in `src/`, bounced to 444 after develop's test suites merged,
now 91. Items below are behavior- or schema-affecting and worth calling out.
* Migration `Version20260517131038`: 18 columns made nullable on synced entities
(`issue`, `project`, `version`, `worklog`) plus 3 DateTime fields, to match property types.
* Migration `Version20260517151632`: 11 `NOT NULL` ManyToOne FKs relaxed to `NULL`;
application-layer `#[Assert\NotNull]` / form validators still enforce required-ness.
* Replaced `?T $prop = null` with non-null defaults on 25 entity properties to satisfy
`NOT NULL` columns; `Worker`/`WorkerGroup` `__toString()` switched from `??` to `?:`.
* `ForecastReportService` rendered empty epic tags — called non-existent `Epic::getName()`;
now uses `Epic::getTitle()`.
* `SubscriptionHandlerService::getVersion()` looked up `Version` by non-existent
`versionId` field; now uses `find($versionId)`.
* `DataProviderService::setTimeSpentSeconds()` silently lost precision passing `float` to an
`int` setter; explicit `(int)` cast added.
* Report services (`ForecastReportService`, `BillableUnbilledHoursReportService`,
`InvoicingRateReportService`) now skip worklogs with null project/issue instead of crashing.
* `SubscriptionController::check()` returns HTTP 400 on null `User::getEmail()`;
`User::getUserIdentifier()` throws on empty email (Symfony requires `non-empty-string`).
* `LeantimeApiService` switched from `json_decode($json, null)` to `json_decode($json, true)`;
all `$data->property` accesses converted to array access. Wire shape unchanged.
* Removed dead code: `readonly string $id` on 3 report-data models, unreachable `break;` after
`throw`, null check on `Row` iterator, unused `$paginator` arg in `SubscriptionRepository`.
* Fixed `Epic::getIssues()` PHPDoc typo (`Collection<int, Epic>` → `Collection<int, Issue>`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I get that this is a big PR, but the size of this entry hurts my eyes, along with the overuse of backticks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done :)

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.

3 participants