diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 27f9284..43a0421 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,9 +16,9 @@ jobs:
strategy:
matrix:
prefer_lowest: ["", "--prefer-lowest"]
- php: ["8.1", "8.2", "8.3"]
+ php: ["8.2", "8.5"]
container:
- image: skpr/php-cli:${{ matrix.php }}-dev-v2-edge
+ image: skpr/php-cli:${{ matrix.php }}-dev-v2-stable
options:
--pull always
--user 1001:1001
@@ -30,6 +30,7 @@ jobs:
- name: 📦 Composer Update
run: composer update --with-all-dependencies --prefer-dist --no-progress --no-interaction ${{ matrix.prefer_lowest }}
- name: 🧹 PHPCS
+ if: matrix.php != '8.5'
run: ./bin/phpcs --report=checkstyle -q | ./bin/cs2pr
- name: 🧹 PHPStan
run: ./bin/phpstan --error-format=github analyse
diff --git a/.gitignore b/.gitignore
index 55b5178..4298530 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
/.phpunit.cache
/bin
/vendor
+/.phpunit.result.cache
diff --git a/composer.json b/composer.json
index 1d4096c..cda1b4c 100644
--- a/composer.json
+++ b/composer.json
@@ -18,17 +18,17 @@
"psr/http-message": "^1.0 || ^2.0",
"psr/http-message-implementation": "*",
"psr/log": "^3.0",
- "symfony/serializer": "^6.2 || ^6.4"
+ "symfony/serializer": "^6.4 || ^7.4"
},
"require-dev": {
- "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
- "guzzlehttp/psr7": "^2.6",
- "http-interop/http-factory-guzzle": "^1.2",
- "php-http/mock-client": "^1.6",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^9.6",
- "previousnext/coding-standard": "^0.1.3",
- "staabm/annotate-pull-request-from-checkstyle": "^1.8"
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.2",
+ "guzzlehttp/psr7": "^2.9",
+ "http-interop/http-factory-guzzle": "^1.2.1",
+ "php-http/mock-client": "^1.6.1",
+ "phpstan/phpstan": "^2.1.50",
+ "phpunit/phpunit": "^11.5.55",
+ "previousnext/coding-standard": "^1.1.1",
+ "staabm/annotate-pull-request-from-checkstyle": "^1.8.6"
},
"autoload": {
"psr-4": {"BomWeather\\": "src/"}
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 3777c04..aab4991 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -1,6 +1,2 @@
parameters:
- ignoreErrors:
- -
- message: "#^Method BomWeather\\\\Util\\\\BaseNormalizer\\:\\:normalize\\(\\) return type with generic class ArrayObject does not specify its types\\: TKey, TValue$#"
- count: 1
- path: src/Util/BaseNormalizer.php
+ ignoreErrors: []
diff --git a/phpstan.neon b/phpstan.neon
index c488226..bea4e79 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -6,6 +6,5 @@ parameters:
paths:
- src
- tests/src
- checkMissingIterableValueType: false
ignoreErrors:
- "#^Call to an undefined method Symfony\\\\Component\\\\Serializer\\\\SerializerInterface\\:\\:denormalize\\(\\)\\.$#"
diff --git a/phpunit.xml b/phpunit.xml
index e63b442..eb20458 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,27 +1,25 @@
+ displayDetailsOnTestsThatTriggerDeprecations="true"
+ displayDetailsOnTestsThatTriggerWarnings="true">
tests/src
-
+
src
-
+
diff --git a/src/BomClient.php b/src/BomClient.php
index 6fae6b5..566bec5 100644
--- a/src/BomClient.php
+++ b/src/BomClient.php
@@ -27,7 +27,7 @@ public function __construct(
protected RequestFactoryInterface $requestFactory,
protected LoggerInterface $logger,
protected ?SerializerInterface $forecastSerializer = NULL,
- protected ?SerializerInterface $observationSerializer = NULL
+ protected ?SerializerInterface $observationSerializer = NULL,
) {
if ($forecastSerializer == NULL) {
$forecastSerializer = ForecastSerializerFactory::create();
diff --git a/src/Forecast/Area.php b/src/Forecast/Area.php
index c377bf4..04c3c8f 100644
--- a/src/Forecast/Area.php
+++ b/src/Forecast/Area.php
@@ -137,7 +137,7 @@ public function setDescription(string $description): Area {
* @return string
* The parent.
*/
- public function getParentAac(): ?string {
+ public function getParentAac(): string {
return $this->parentAac;
}
diff --git a/src/Forecast/Forecast.php b/src/Forecast/Forecast.php
index 0bac899..fb6af06 100644
--- a/src/Forecast/Forecast.php
+++ b/src/Forecast/Forecast.php
@@ -196,7 +196,7 @@ public function addLocation(Area $location): Forecast {
/**
* Gets the issue time.
*/
- public function getIssueTime(): ?\DateTimeImmutable {
+ public function getIssueTime(): \DateTimeImmutable {
return $this->issueTime;
}
diff --git a/src/Forecast/ForecastPeriod.php b/src/Forecast/ForecastPeriod.php
index 13a79c6..eb1b522 100644
--- a/src/Forecast/ForecastPeriod.php
+++ b/src/Forecast/ForecastPeriod.php
@@ -200,7 +200,7 @@ public function getProbabilityOfPrecipitation(): ?string {
* Sets the probability of precipitation.
*/
public function setProbabilityOfPrecipitation(
- string $probabilityOfPrecipitation
+ string $probabilityOfPrecipitation,
): ForecastPeriod {
$this->probabilityOfPrecipitation = $probabilityOfPrecipitation;
return $this;
diff --git a/src/Forecast/Serializer/AreaNormalizer.php b/src/Forecast/Serializer/AreaNormalizer.php
index 990dfb5..865381a 100644
--- a/src/Forecast/Serializer/AreaNormalizer.php
+++ b/src/Forecast/Serializer/AreaNormalizer.php
@@ -14,12 +14,26 @@
*/
class AreaNormalizer extends BaseNormalizer {
+ /**
+ * The supported interface or class.
+ *
+ * @var string|array
+ */
protected string|array $supportedInterfaceOrClass = Area::class;
/**
* {@inheritdoc}
+ *
+ * @param mixed $data
+ * Data to restore.
+ * @param string $type
+ * The expected class to instantiate.
+ * @param string|null $format
+ * Format the given data was extracted from.
+ * @param array $context
+ * Context options for the denormalizer.
*/
- public function denormalize($data, $type, $format = NULL, array $context = []) {
+ public function denormalize(mixed $data, string $type, ?string $format = NULL, array $context = []): mixed {
if (!$this->serializer instanceof DenormalizerInterface) {
throw new \RuntimeException('The serializer must implement the DenormalizerInterface.');
}
diff --git a/src/Forecast/Serializer/ForecastNormalizer.php b/src/Forecast/Serializer/ForecastNormalizer.php
index 7c3514e..4ffa966 100644
--- a/src/Forecast/Serializer/ForecastNormalizer.php
+++ b/src/Forecast/Serializer/ForecastNormalizer.php
@@ -15,14 +15,25 @@
class ForecastNormalizer extends BaseNormalizer {
/**
- * {@inheritdoc}
+ * The supported interface or class.
+ *
+ * @var string|array
*/
protected string|array $supportedInterfaceOrClass = Forecast::class;
/**
* {@inheritdoc}
+ *
+ * @param mixed $data
+ * Data to restore.
+ * @param string $type
+ * The expected class to instantiate.
+ * @param string|null $format
+ * Format the given data was extracted from.
+ * @param array $context
+ * Context options for the denormalizer.
*/
- public function denormalize($data, $type, $format = NULL, array $context = []) {
+ public function denormalize(mixed $data, string $type, ?string $format = NULL, array $context = []): mixed {
if (!$this->serializer instanceof DenormalizerInterface) {
throw new \RuntimeException('The serializer must implement the DenormalizerInterface.');
}
@@ -45,7 +56,7 @@ public function denormalize($data, $type, $format = NULL, array $context = []) {
/**
* Sets the area value.
*
- * @param array $area
+ * @param array $area
* The area data.
* @param \BomWeather\Forecast\Forecast $forecast
* The forecast.
diff --git a/src/Forecast/Serializer/ForecastPeriodNormalizer.php b/src/Forecast/Serializer/ForecastPeriodNormalizer.php
index 70dc9cc..81fd3ed 100644
--- a/src/Forecast/Serializer/ForecastPeriodNormalizer.php
+++ b/src/Forecast/Serializer/ForecastPeriodNormalizer.php
@@ -12,12 +12,26 @@
*/
class ForecastPeriodNormalizer extends BaseNormalizer {
+ /**
+ * The supported interface or class.
+ *
+ * @var string|array
+ */
protected string|array $supportedInterfaceOrClass = ForecastPeriod::class;
/**
* {@inheritdoc}
+ *
+ * @param mixed $data
+ * Data to restore.
+ * @param string $type
+ * The expected class to instantiate.
+ * @param string|null $format
+ * Format the given data was extracted from.
+ * @param array $context
+ * Context options for the denormalizer.
*/
- public function denormalize($data, $type, $format = NULL, array $context = []) {
+ public function denormalize(mixed $data, string $type, ?string $format = NULL, array $context = []): mixed {
$period = (new ForecastPeriod())
->setStartTime($this->serializer->denormalize($data['@start-time-utc'], \DateTimeImmutable::class))
->setEndTime($this->serializer->denormalize($data['@end-time-utc'], \DateTimeImmutable::class));
@@ -51,7 +65,7 @@ public function denormalize($data, $type, $format = NULL, array $context = []) {
/**
* Set an element value.
*
- * @param array $element
+ * @param array $element
* The element array.
* @param \BomWeather\Forecast\ForecastPeriod $period
* The period.
@@ -80,7 +94,7 @@ protected function setElementValue(array $element, ForecastPeriod $period): void
/**
* Sets a text value.
*
- * @param array $text
+ * @param array $text
* The text array.
* @param \BomWeather\Forecast\ForecastPeriod $period
* The period.
diff --git a/src/Observation/Observation.php b/src/Observation/Observation.php
index 3deef42..1830d3a 100644
--- a/src/Observation/Observation.php
+++ b/src/Observation/Observation.php
@@ -79,7 +79,7 @@ public function getTemperature(): ?Temperature {
/**
* Sets the Temperature.
*/
- public function setTemperature(Temperature $temperature): ?Observation {
+ public function setTemperature(Temperature $temperature): self {
$this->temperature = $temperature;
return $this;
}
diff --git a/src/Observation/Serializer/ObservationListNormalizer.php b/src/Observation/Serializer/ObservationListNormalizer.php
index 86c2683..a4454c8 100644
--- a/src/Observation/Serializer/ObservationListNormalizer.php
+++ b/src/Observation/Serializer/ObservationListNormalizer.php
@@ -14,12 +14,26 @@
*/
class ObservationListNormalizer extends BaseNormalizer {
+ /**
+ * The supported interface or class.
+ *
+ * @var string|array
+ */
protected string|array $supportedInterfaceOrClass = ObservationList::class;
/**
* {@inheritdoc}
+ *
+ * @param mixed $data
+ * Data to restore.
+ * @param string $type
+ * The expected class to instantiate.
+ * @param string|null $format
+ * Format the given data was extracted from.
+ * @param array $context
+ * Context options for the denormalizer.
*/
- public function denormalize($data, $type, $format = NULL, array $context = []) {
+ public function denormalize(mixed $data, string $type, ?string $format = NULL, array $context = []): mixed {
if (!$this->serializer instanceof DenormalizerInterface) {
throw new \RuntimeException('The serializer must implement the DenormalizerInterface.');
}
diff --git a/src/Observation/Serializer/ObservationNormalizer.php b/src/Observation/Serializer/ObservationNormalizer.php
index 283a86c..f24a698 100644
--- a/src/Observation/Serializer/ObservationNormalizer.php
+++ b/src/Observation/Serializer/ObservationNormalizer.php
@@ -16,12 +16,26 @@
*/
class ObservationNormalizer extends BaseNormalizer {
+ /**
+ * The supported interface or class.
+ *
+ * @var string|array
+ */
protected string|array $supportedInterfaceOrClass = Observation::class;
/**
* {@inheritdoc}
+ *
+ * @param mixed $data
+ * Data to restore.
+ * @param string $type
+ * The expected class to instantiate.
+ * @param string|null $format
+ * Format the given data was extracted from.
+ * @param array $context
+ * Context options for the denormalizer.
*/
- public function denormalize($data, $type, $format = NULL, array $context = []) {
+ public function denormalize(mixed $data, string $type, ?string $format = NULL, array $context = []): mixed {
$station = (new Station())
->setId($data['wmo'])
->setLatitude($data['lat'])
diff --git a/src/Util/BaseNormalizer.php b/src/Util/BaseNormalizer.php
index 95cbcd8..9f867e3 100644
--- a/src/Util/BaseNormalizer.php
+++ b/src/Util/BaseNormalizer.php
@@ -15,15 +15,25 @@ abstract class BaseNormalizer extends AbstractNormalizer {
/**
* {@inheritdoc}
+ *
+ * @param mixed $object
+ * Object to normalize.
+ * @param string|null $format
+ * Format the normalization result will be encoded as.
+ * @param array $context
+ * Context options for the normalizer.
+ *
+ * @return array|\ArrayObject|bool|float|int|string|null
+ * The normalized data.
*/
- public function normalize(mixed $object, string $format = NULL, array $context = []) {
+ public function normalize(mixed $object, ?string $format = NULL, array $context = []): array|\ArrayObject|bool|float|int|string|null {
throw new \RuntimeException("Method not implemented.");
}
/**
* Checks whether the array is associative.
*
- * @param array $array
+ * @param array $array
* The array.
*
* @return bool
diff --git a/src/Util/ClassNameSupportNormalizerTrait.php b/src/Util/ClassNameSupportNormalizerTrait.php
index 1c93372..494a3eb 100644
--- a/src/Util/ClassNameSupportNormalizerTrait.php
+++ b/src/Util/ClassNameSupportNormalizerTrait.php
@@ -11,16 +11,23 @@ trait ClassNameSupportNormalizerTrait {
/**
* The interface or class that this Normalizer supports.
+ *
+ * @var string|array
*/
protected string|array $supportedInterfaceOrClass;
/**
* The format this Normalizer supports.
+ *
+ * @var string|array
*/
protected string|array $format;
/**
* Gets the string or array of supported classes.
+ *
+ * @return string|array
+ * The supported class or classes.
*/
public function getSupportedInterfaceOrClass(): string|array {
return $this->supportedInterfaceOrClass;
@@ -28,6 +35,9 @@ public function getSupportedInterfaceOrClass(): string|array {
/**
* Sets the string or array of supported classes.
+ *
+ * @param string|array $supported_interface_or_class
+ * The supported class or classes.
*/
public function setSupportedInterfaceOrClass(string|array $supported_interface_or_class): self {
$this->supportedInterfaceOrClass = $supported_interface_or_class;
@@ -36,8 +46,33 @@ public function setSupportedInterfaceOrClass(string|array $supported_interface_o
/**
* {@inheritdoc}
+ *
+ * @param string|null $format
+ * The format being (de-)serialized from or into.
+ *
+ * @return array
+ * The supported types.
*/
- public function supportsNormalization(mixed $data, string $format = NULL /* , array $context = [] */): bool {
+ public function getSupportedTypes(?string $format): array {
+ $supported = (array) $this->supportedInterfaceOrClass;
+ $result = [];
+ foreach ($supported as $class) {
+ $result[$class] = FALSE;
+ }
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param mixed $data
+ * Data to normalize.
+ * @param string|null $format
+ * The format being (de-)serialized from or into.
+ * @param array $context
+ * Context options for the normalizer.
+ */
+ public function supportsNormalization(mixed $data, ?string $format = NULL, array $context = []): bool {
// If we aren't dealing with an object or the format is not supported return
// now.
if (!\is_object($data) || !$this->checkFormat($format)) {
@@ -46,15 +81,24 @@ public function supportsNormalization(mixed $data, string $format = NULL /* , ar
$supported = (array) $this->supportedInterfaceOrClass;
- return (bool) \array_filter($supported, function ($name) use ($data) {
+ return (bool) \array_filter($supported, static function ($name) use ($data) {
return $data instanceof $name;
});
}
/**
* {@inheritdoc}
+ *
+ * @param mixed $data
+ * Data to denormalize from.
+ * @param string $type
+ * The class to which the data should be denormalized.
+ * @param string|null $format
+ * The format being deserialized from.
+ * @param array $context
+ * Context options for the denormalizer.
*/
- public function supportsDenormalization(mixed $data, string $type, string $format = NULL /* , array $context = [] */): bool {
+ public function supportsDenormalization(mixed $data, string $type, ?string $format = NULL, array $context = []): bool {
// If the format is not supported return now.
if (!$this->checkFormat($format)) {
return FALSE;
@@ -62,7 +106,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma
$supported = (array) $this->supportedInterfaceOrClass;
- $subclass_check = function ($name) use ($type) {
+ $subclass_check = static function ($name) use ($type) {
return (\class_exists($name) || \interface_exists($name)) && \is_subclass_of($type,
$name, TRUE);
};
@@ -78,7 +122,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma
* TRUE if the format is supported, FALSE otherwise. If no format is
* specified this will return TRUE.
*/
- protected function checkFormat(string $format = NULL): bool {
+ protected function checkFormat(?string $format = NULL): bool {
if (!isset($format) || !isset($this->format)) {
return TRUE;
}
diff --git a/tests/src/Functional/BomClientTest.php b/tests/src/Functional/BomClientTest.php
index 3dc1af1..cd3599d 100644
--- a/tests/src/Functional/BomClientTest.php
+++ b/tests/src/Functional/BomClientTest.php
@@ -7,6 +7,7 @@
use BomWeather\BomClient;
use GuzzleHttp\Psr7\Stream;
use Http\Mock\Client;
+use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
@@ -14,13 +15,13 @@
use Psr\Log\NullLogger;
/**
- * @coversDefaultClass \BomWeather\BomClient
+ * Tests the BOM client.
*/
+#[CoversClass(BomClient::class)]
class BomClientTest extends TestCase {
/**
- * @covers ::__construct()
- * @covers ::getForecast()
+ * Tests the getForecast method.
*/
public function testGetForecast(): void {
$logger = new NullLogger();
@@ -41,8 +42,7 @@ public function testGetForecast(): void {
}
/**
- * @covers ::__construct()
- * @covers ::getObservationList()
+ * Tests the getObservationList method.
*/
public function testGetObservation(): void {
$logger = new NullLogger();
diff --git a/tests/src/Unit/Forecast/Serializer/ForecastSerializerTest.php b/tests/src/Unit/Forecast/Serializer/ForecastSerializerTest.php
index 80aa30a..66c3b67 100644
--- a/tests/src/Unit/Forecast/Serializer/ForecastSerializerTest.php
+++ b/tests/src/Unit/Forecast/Serializer/ForecastSerializerTest.php
@@ -6,15 +6,17 @@
use BomWeather\Forecast\Forecast;
use BomWeather\Forecast\Serializer\ForecastSerializerFactory;
+use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
/**
- * @coversDefaultClass \BomWeather\Forecast\Serializer\ForecastSerializerFactory
+ * Tests the forecast serializer.
*/
+#[CoversClass(ForecastSerializerFactory::class)]
class ForecastSerializerTest extends TestCase {
/**
- * @covers ::create
+ * Tests deserialization of Sydney forecast data.
*/
public function testDeserializeSydney(): void {
$factory = new ForecastSerializerFactory();
@@ -24,8 +26,6 @@ public function testDeserializeSydney(): void {
/** @var \BomWeather\Forecast\Forecast $forecast */
$forecast = $serializer->deserialize($xml, Forecast::class, 'xml');
-
- $this->assertNotNull($forecast);
$this->assertEquals('2018-06-20T21:41:57+00:00', $forecast->getIssueTime()->format(DATE_RFC3339));
// Regions.
diff --git a/tests/src/Unit/Observation/Serializer/ObservationSerializerTest.php b/tests/src/Unit/Observation/Serializer/ObservationSerializerTest.php
index f55146a..3383944 100644
--- a/tests/src/Unit/Observation/Serializer/ObservationSerializerTest.php
+++ b/tests/src/Unit/Observation/Serializer/ObservationSerializerTest.php
@@ -6,15 +6,17 @@
use BomWeather\Observation\ObservationList;
use BomWeather\Observation\Serializer\ObservationSerializerFactory;
+use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
/**
- * @coversDefaultClass \BomWeather\Observation\Serializer\ObservationSerializerFactory
+ * Tests the observation serializer.
*/
+#[CoversClass(ObservationSerializerFactory::class)]
class ObservationSerializerTest extends TestCase {
/**
- * @covers ::create()
+ * Tests deserialization of observation data.
*/
public function testDeserialize(): void {
$serializer = ObservationSerializerFactory::create();
@@ -22,9 +24,6 @@ public function testDeserialize(): void {
/** @var \BomWeather\Observation\ObservationList $observationList */
$observationList = $serializer->deserialize($json, ObservationList::class, 'json');
-
- $this->assertNotNull($observationList);
-
$this->assertEquals("Issued at 9:31 am EST Monday 25 June 2018", $observationList->getRefreshMessage());
$this->assertCount(144, $observationList->getObservations());