diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 11d5158..5da3e14 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,7 +10,6 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- # phlix-shared requires PHP ^8.3, so the matrix matches.
php: ['8.3', '8.4']
steps:
- uses: actions/checkout@v6
@@ -19,7 +18,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- coverage: none
+ coverage: pcov
tools: composer:v2
- name: Install dependencies
@@ -27,3 +26,9 @@ jobs:
- name: Run PHPUnit
run: vendor/bin/phpunit --colors=always
+
+ - name: Run PHPStan
+ run: vendor/bin/phpstan analyse src --level=9
+
+ - name: Run PHPCS
+ run: vendor/bin/phpcs src --standard=PSR12
diff --git a/composer.json b/composer.json
index 5bc4c9e..8b74416 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,9 @@
"detain/phlix-shared": "^0.6"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpstan/phpstan": "^2.2",
+ "phpunit/phpunit": "^10.0",
+ "squizlabs/php_codesniffer": "^4.0"
},
"repositories": [
{ "type": "vcs", "url": "https://github.com/detain/phlix-shared.git" }
@@ -29,5 +31,9 @@
"config": {
"optimize-autoloader": true,
"sort-packages": true
+ },
+ "scripts": {
+ "phpstan": "vendor/bin/phpstan analyse src --level=9",
+ "phpcs": "vendor/bin/phpcs src --standard=PSR12"
}
}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..43a7a11
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,7 @@
+
+
+ PSR-12 coding standard for phlix-plugin-example
+ src
+ vendor/
+
+
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..3e639cd
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,4 @@
+parameters:
+ level: 9
+ paths:
+ - src
diff --git a/phpunit.xml b/phpunit.xml
index 8cc71c9..406f480 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -14,4 +14,9 @@
src
+
+
+
+
+
diff --git a/src/HelloMetadataProvider.php b/src/HelloMetadataProvider.php
index 8dd8df5..ca429ce 100644
--- a/src/HelloMetadataProvider.php
+++ b/src/HelloMetadataProvider.php
@@ -22,15 +22,15 @@
* progressively replace {@see lookup()} with real metadata lookups
* against TMDB, TVDB, Fanart.tv, or any other source.
*
- * ## Lifecycle notes
- *
- * - {@see onEnable()} keeps state minimal — it only stashes the host
- * container so {@see lookup()} can resolve services lazily if a
- * future implementation needs them.
- * - {@see subscribedEvents()} returns an empty array; this plugin does
- * not listen for PSR-14 events. A real metadata provider can leave
- * this empty too — Phase A's `MetadataManager` invokes providers
- * directly rather than via the dispatcher.
+ * ## Lifecycle notes
+ *
+ * - {@see onEnable()} is a no-op for the reference plugin; it accepts
+ * the host container to satisfy the contract but does not retain it.
+ * Real plugins that need a container should store it as a property.
+ * - {@see subscribedEvents()} returns an empty array; this plugin does
+ * not listen for PSR-14 events. A real metadata provider can leave
+ * this empty too — Phase A's `MetadataManager` invokes providers
+ * directly rather than via the dispatcher.
*
* ## Provenance
*
@@ -65,15 +65,6 @@ final class HelloMetadataProvider implements LifecycleInterface
*/
private string $greeting;
- /**
- * Host container handle stashed during {@see onEnable()}. Real
- * provider implementations resolve `LoggerInterface`, HTTP clients,
- * or cache services through it; the example does not yet need it
- * but keeping the reference makes the extension point obvious for
- * authors copying this class as a starter.
- */
- private ?ContainerInterface $container = null;
-
/**
* @param string $greeting Override for the greeting returned by
* {@see lookup()}. Tests pass a custom value; production
@@ -87,10 +78,8 @@ public function __construct(string $greeting = self::DEFAULT_GREETING)
/**
* Loader hook called once when the plugin is enabled.
*
- * Stashes the host container so later metadata lookups can resolve
- * services lazily. Real providers might also open an HTTP client or
- * warm a cache here — keep it cheap; the loader is in the request
- * path.
+ * No-op for the reference plugin. Real plugins that need the host
+ * container should store it as a property here.
*
* @param ContainerInterface $container Host PSR-11 container.
*
@@ -100,15 +89,14 @@ public function __construct(string $greeting = self::DEFAULT_GREETING)
*/
public function onEnable(ContainerInterface $container): void
{
- $this->container = $container;
}
/**
* Loader hook called once when the plugin is disabled.
*
- * Releases the stashed container reference. Plugins that opened
- * clients in {@see onEnable()} should close them here so the
- * lifecycle is symmetric.
+ * No-op for the reference plugin. Real plugins that opened resources
+ * in {@see onEnable()} should close them here so the lifecycle is
+ * symmetric.
*
* @return void
*
@@ -116,7 +104,6 @@ public function onEnable(ContainerInterface $container): void
*/
public function onDisable(): void
{
- $this->container = null;
}
/**