Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@
"mehedidracula.php-namespace-resolver"
],
"settings": {
"php.validate.executablePath": "/usr/local/bin/php"
"php.validate.executablePath": "/usr/local/bin/php",
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.profiles.linux": {
"bash": {
"path": "/bin/bash",
"args": ["-l"]
}
}
}
}
},
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/phpstan-baseline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: PHPStan Baseline Check

on:
pull_request:
branches: [ main, master ]
paths:
- 'src/**/*.php'

jobs:
phpstan:
runs-on: ubuntu-latest

strategy:
matrix:
php-version: ['8.4']
fail-fast: false

steps:
- uses: actions/checkout@v5

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: dom, json, libxml
coverage: xdebug

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-${{ matrix.php-version }}-

- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Run PHPStan with baseline
run: vendor/bin/phpstan analyse --error-format=github
63 changes: 63 additions & 0 deletions docs/codecontributions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Code Quality

This project uses PHPStan for static analysis and Rector for automated code refactoring to maintain high code quality standards.

## PHPStan - Static Analysis

PHPStan analyzes the code for potential issues and type safety problems. The configuration is stored in `phpstan.neon.dist`.

### Generate a new baseline
When introducing PHPStan to legacy code or after major refactoring, you can create a baseline to suppress existing errors:
```bash
vendor/bin/phpstan analyse --generate-baseline
```

### Run analysis
To analyze the codebase and find issues:
```bash
vendor/bin/phpstan analyse
```

### Configuration
- Configuration file: `phpstan.neon.dist`
- Current analysis level: 5
- Baseline file: `phpstan-baseline.neon` (suppresses known issues)

## Rector - Automated Refactoring

Rector automatically modernizes PHP code and applies coding standards. The configuration is stored in `rector.php`.

### Preview changes (recommended first step)
Run a dry-run to see what changes Rector would make without actually modifying files:
```bash
vendor/bin/rector process --dry-run
```

### Apply changes
Apply the refactoring rules to actually modify the code:
```bash
vendor/bin/rector process
```

### Debug mode
To see detailed information about what Rector is doing:
```bash
vendor/bin/rector process --dry-run --debug
```

### Finding new rules
To discover additional Rector rules for your project, visit: https://getrector.com/find-rule

## Workflow

1. **Before making changes**: Run `vendor/bin/phpstan analyse` to check current code quality
2. **Use Rector for improvements**: Run `vendor/bin/rector process --dry-run` to preview automated fixes
3. **Apply safe changes**: Run `vendor/bin/rector process` to apply the changes
4. **Verify with tests**: Run `make test` to ensure changes don't break functionality
5. **Final analysis**: Run `vendor/bin/phpstan analyse` to confirm improvements

## CI/CD Integration

Both PHPStan and Rector are integrated into the CI pipeline to ensure:
- No new PHPStan errors are introduced (beyond the baseline)
- Code follows modern PHP practices through Rector
4 changes: 4 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
site_name: feed-io Documentation
theme:
name: material

nav:
- Home: index.md
- Code Quality: codecontributions.md
49 changes: 49 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
parameters:
ignoreErrors:
-
message: '#^Call to an undefined method FeedIo\\Feed\\ItemInterface\:\:setHostInContent\(\)\.$#'
identifier: method.notFound
count: 1
path: src/FeedIo/Feed.php

-
message: '#^Call to an undefined method FeedIo\\Feed\\ItemInterface\:\:setLinkForAnalysis\(\)\.$#'
identifier: method.notFound
count: 1
path: src/FeedIo/Parser/XmlParser.php

-
message: '#^Deprecated in PHP 8\.0\: Required parameter \$url follows optional parameter \$modifiedSince\.$#'
identifier: parameter.requiredAfterOptional
count: 1
path: src/FeedIo/Reader/Result.php

-
message: '#^Deprecated in PHP 8\.1\: Required parameter \$response follows optional parameter \$modifiedSince\.$#'
identifier: parameter.requiredAfterOptional
count: 1
path: src/FeedIo/Reader/Result.php

-
message: '#^Offset float on list in isset\(\) does not exist\.$#'
identifier: isset.offset
count: 1
path: src/FeedIo/Reader/Result/UpdateStats.php

-
message: '#^Call to an undefined method FeedIo\\Feed\\NodeInterface\:\:getHostFromLink\(\)\.$#'
identifier: method.notFound
count: 1
path: src/FeedIo/Rule/Atom/Link.php

-
message: '#^Call to an undefined method FeedIo\\Feed\\NodeInterface\:\:getHostFromLink\(\)\.$#'
identifier: method.notFound
count: 1
path: src/FeedIo/Rule/Link.php

-
message: '#^PHPDoc tag @var with type FeedIo\\Reader\\FixerAbstract is not subtype of native type FeedIo\\Reader\\Fixer\\HttpLastModified\|FeedIo\\Reader\\Fixer\\PublicId\.$#'
identifier: varTag.nativeType
count: 1
path: src/FeedIo/Specification.php
3 changes: 3 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
includes:
- phpstan-baseline.neon

parameters:
errorFormat: table
level: 5
Expand Down
2 changes: 1 addition & 1 deletion src/FeedIo/Adapter/ClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ interface ClientInterface
* @throws \FeedIo\Adapter\ServerErrorException
* @return \FeedIo\Adapter\ResponseInterface
*/
public function getResponse(string $url, DateTime $modifiedSince = null): ResponseInterface;
public function getResponse(string $url, ?DateTime $modifiedSince = null): ResponseInterface;
}
2 changes: 1 addition & 1 deletion src/FeedIo/Adapter/FileSystem/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Client implements ClientInterface
* @return \FeedIo\Adapter\ResponseInterface
*@throws \FeedIo\Adapter\NotFoundException
*/
public function getResponse(string $path, DateTime $modifiedSince = null): ResponseInterface
public function getResponse(string $path, ?DateTime $modifiedSince = null): ResponseInterface
{
if (file_exists($path)) {
return new Response(
Expand Down
4 changes: 2 additions & 2 deletions src/FeedIo/Adapter/Http/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function __construct(private readonly PsrClientInterface $client)
* @return ResponseInterface
* @throws ClientExceptionInterface
*/
public function getResponse(string $url, DateTime $modifiedSince = null): ResponseInterface
public function getResponse(string $url, ?DateTime $modifiedSince = null): ResponseInterface
{
if ($modifiedSince) {
$headResponse = $this->request('HEAD', $url, $modifiedSince);
Expand All @@ -44,7 +44,7 @@ public function getResponse(string $url, DateTime $modifiedSince = null): Respon
* @return ResponseInterface
* @throws ClientExceptionInterface
*/
protected function request(string $method, string $url, DateTime $modifiedSince = null): ResponseInterface
protected function request(string $method, string $url, ?DateTime $modifiedSince = null): ResponseInterface
{
$headers = [];

Expand Down
2 changes: 1 addition & 1 deletion src/FeedIo/Adapter/NullClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class NullClient implements ClientInterface
* @param DateTime|null $modifiedSince
* @return \FeedIo\Adapter\ResponseInterface
*/
public function getResponse(string $url, DateTime $modifiedSince = null): ResponseInterface
public function getResponse(string $url, ?DateTime $modifiedSince = null): ResponseInterface
{
return new NullResponse();
}
Expand Down
2 changes: 1 addition & 1 deletion src/FeedIo/Explorer.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function discover(string $url): array
return $feeds;
}

protected function extractFeeds(string $html, string $url = null): array
protected function extractFeeds(string $html, ?string $url = null): array
{
$dom = new DOMDocument();
$dom->loadHTML($html);
Expand Down
8 changes: 4 additions & 4 deletions src/FeedIo/Feed.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function getUrl(): ?string
* @param string|null $url
* @return FeedInterface
*/
public function setUrl(string $url = null): FeedInterface
public function setUrl(?string $url = null): FeedInterface
{
$this->url = $url;

Expand All @@ -64,7 +64,7 @@ public function getDescription(): ?string
return $this->description;
}

public function setDescription(string $description = null): FeedInterface
public function setDescription(?string $description = null): FeedInterface
{
$this->description = $description;

Expand All @@ -76,7 +76,7 @@ public function getLanguage(): ?string
return $this->language;
}

public function setLanguage(string $language = null): FeedInterface
public function setLanguage(?string $language = null): FeedInterface
{
$this->language = $language;

Expand All @@ -88,7 +88,7 @@ public function getLogo(): ?string
return $this->logo;
}

public function setLogo(string $logo = null): FeedInterface
public function setLogo(?string $logo = null): FeedInterface
{
$this->logo = $logo;

Expand Down
4 changes: 2 additions & 2 deletions src/FeedIo/Feed/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public function getSummary(): ?string
* @param string|null $summary
* @return ItemInterface
*/
public function setSummary(string $summary = null): ItemInterface
public function setSummary(?string $summary = null): ItemInterface
{
$this->summary = $summary;

Expand All @@ -90,7 +90,7 @@ public function getContent(): ?string
* @param string|null $content
* @return ItemInterface
*/
public function setContent(string $content = null): ItemInterface
public function setContent(?string $content = null): ItemInterface
{
$this->content = $content;

Expand Down
6 changes: 3 additions & 3 deletions src/FeedIo/Feed/Item/Author.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function getName(): ?string
* @param string|null $name
* @return AuthorInterface
*/
public function setName(string $name = null): AuthorInterface
public function setName(?string $name = null): AuthorInterface
{
$this->name = $name;

Expand All @@ -45,7 +45,7 @@ public function getUri(): ?string
* @param string|null $uri
* @return AuthorInterface
*/
public function setUri(string $uri = null): AuthorInterface
public function setUri(?string $uri = null): AuthorInterface
{
$this->uri = $uri;

Expand All @@ -64,7 +64,7 @@ public function getEmail(): ?string
* @param string|null $email
* @return AuthorInterface
*/
public function setEmail(string $email = null): AuthorInterface
public function setEmail(?string $email = null): AuthorInterface
{
$this->email = $email;

Expand Down
6 changes: 3 additions & 3 deletions src/FeedIo/Feed/Item/AuthorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function getName(): ?string;
* @param string $name
* @return AuthorInterface
*/
public function setName(string $name = null): AuthorInterface;
public function setName(?string $name = null): AuthorInterface;

/**
* @return string
Expand All @@ -30,7 +30,7 @@ public function getUri(): ?string;
* @param string $uri
* @return AuthorInterface
*/
public function setUri(string $uri = null): AuthorInterface;
public function setUri(?string $uri = null): AuthorInterface;

/**
* @return string
Expand All @@ -41,5 +41,5 @@ public function getEmail(): ?string;
* @param string $email
* @return AuthorInterface
*/
public function setEmail(string $email = null): AuthorInterface;
public function setEmail(?string $email = null): AuthorInterface;
}
4 changes: 2 additions & 2 deletions src/FeedIo/Feed/ItemInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function getSummary(): ?string;
* @param string|null $summary
* @return ItemInterface
*/
public function setSummary(string $summary = null): ItemInterface;
public function setSummary(?string $summary = null): ItemInterface;

/**
* Returns the item's content. Valid for JSONFeed and Atom formats only
Expand All @@ -75,5 +75,5 @@ public function getContent(): ?string;
* @param string|null $content
* @return ItemInterface
*/
public function setContent(string $content = null): ItemInterface;
public function setContent(?string $content = null): ItemInterface;
}
Loading