Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4ccce06
PHP 8 deprecations fix
Jul 29, 2026
4845474
Drop PHP 7.1, 7.2 and 7.3 support
Jul 29, 2026
1f8622a
Import globally namespaced and fully qualified classes
Jul 29, 2026
4ad6c19
Add 3.5.0 changelog entry
Jul 29, 2026
98c9236
Mention import cleanup in changelog
Jul 29, 2026
34549b3
Replace long array syntax with short syntax
Jul 29, 2026
1fb232f
Mention short array syntax in changelog
Jul 29, 2026
d7b2c9a
Address review feedback
Jul 29, 2026
ca49614
Set default property values in constructors
Jul 29, 2026
0392781
Defer getIterator() return type to 4.0.0, release as 3.5.0
Jul 31, 2026
e6c15ec
Add regression tests for default initialisation
Jul 31, 2026
99074be
Initialise Result::$items in the constructor
Jul 31, 2026
69e1057
Report null date input accurately in DateNormalizer
Jul 31, 2026
885064c
Move DistributedNormalizer defaults back to property declarations
Jul 31, 2026
3a1a721
Drop redundant $offset redeclaration in FollowUpFilter
Jul 31, 2026
367749b
Initialise DistributedNormalizer defaults in the constructor
Jul 31, 2026
6ab6876
Default Result::$items on the property declaration
Jul 31, 2026
ebb9112
List the DateNormalizer message change under Changed
Jul 31, 2026
5186422
Remove stray blank lines after class opening braces
Jul 31, 2026
c524570
Import ReturnTypeWillChange instead of a leading backslash
Jul 31, 2026
e370696
Correct calculateTotalCount() return docblock
Jul 31, 2026
85e80dc
Move the Filter test fixture into its own autoloadable file
Jul 31, 2026
e228a10
Document the two behavioural changes missing from the changelog
Jul 31, 2026
6da6e47
Move DistributedNormalizer defaults back to property declarations
Jul 31, 2026
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
16 changes: 2 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ jobs:

matrix:
php:
- '7.1'
- '7.2'
- '7.3'
- '7.4'
- '8.0'
- '8.1'
Expand All @@ -35,17 +32,13 @@ jobs:
dependency:
- 'highest'
include:
- { php: '7.1', symfony: '3.*', dependency: 'lowest' }
- { php: '7.4', symfony: '3.*', dependency: 'lowest' }
exclude:
- { php: '8.0', symfony: '3.*' }
- { php: '8.1', symfony: '3.*' }
- { php: '8.2', symfony: '3.*' }
- { php: '8.3', symfony: '3.*' }
- { php: '8.4', symfony: '3.*' }
- { php: '7.1', symfony: '5.*' }
- { php: '7.1', symfony: '6.*' }
- { php: '7.2', symfony: '6.*' }
- { php: '7.3', symfony: '6.*' }
- { php: '7.4', symfony: '6.*' }
- { php: '8.0', symfony: '6.*' }

Expand All @@ -60,12 +53,7 @@ jobs:
tools: flex

- name: Ignore specific Composer audit advisory
run: |
if [[ "${{ matrix.php }}" == "7.1" ]]; then
echo "COMPOSER_AUDIT_BLOCK_INSECURE=0" >> $GITHUB_ENV
else
composer config --global audit.ignore "PKSA-w2tw-kmfg-rt9s"
fi
run: composer config --global audit.ignore "PKSA-w2tw-kmfg-rt9s"

- name: Install dependencies
uses: ramsey/composer-install@v2
Expand Down
39 changes: 39 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,45 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 3.5.0
### Changed
- `DateNormalizer::mapToEntity()` rejects `null` up front instead of passing it to
`DateTime::createFromFormat()`, resolving a PHP 8.1 deprecation. `null` still raises
`InvalidDataException`, so `catch` blocks are unaffected, but the message changes from
`Provided date format is invalid` to `Date must be provided` — the old text blamed the
configured format for what is really a missing input. Consumers that match on
`getMessage()` rather than the exception type, such as API error-mapping layers, need to
account for the new string.
- Narrowed the `phpunit/phpunit` development requirement to `^9.3` — the version that introduced
the `<coverage>` configuration element used by `phpunit.xml.dist`.
- Replaced leading-backslash class references with `use` statements throughout the library —
global classes (`ArrayIterator`, `ArrayObject`, `DateTime`, `DateTimeZone`, `Exception` and
the SPL exceptions) and fully qualified `Paysera\...` references in docblocks. No behaviour
change.
- Replaced long array syntax (`array(...)`) with short syntax (`[...]`) throughout the library.
No behaviour change.

### Removed
- Dropped support for PHP 7.1, 7.2 and 7.3. Minimum supported version is now PHP 7.4. Projects
still on those versions resolve to 3.4.x and are unaffected.

### Fixed
- `Result::getIterator()` is marked `#[\ReturnTypeWillChange]`, silencing the PHP 8.1 tentative
return type deprecation without changing the signature. The native `\Traversable` return type
is deferred to 4.0.0, where it will be batched with the other type additions.
- `CamelCaseToSnakeCaseConverter::convert()` no longer passes `null` to `preg_replace()`,
resolving a PHP 8.1 deprecation. Passing `null` still returns an empty string as before.
- `FollowUpFilter` no longer redeclares `$offset` without an initialiser. The shadowing
declaration gave it a `null` default where `Filter` declares `0`; it now inherits the parent
default. Instances built through the constructor were always assigned an offset there and are
unaffected.
- `Result::$items` now defaults to an empty array, so iterating a `Result` whose items were never
set no longer raises a `TypeError` on PHP 8 (an `InvalidArgumentException` on PHP 7.4) and
`getItems()` honours its documented `@return mixed[]`. The default lives on the property
declaration rather than in the constructor, so it also applies to instances built without one —
`ReflectionClass::newInstanceWithoutConstructor()`, and the ORM hydration and mocking that build
on it.

## 3.4.0
### Added
- PHP 8.4 support, removed implicitly nullable parameter declarations.
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
}
},
"require-dev": {
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
"phpunit/phpunit": "^9.3"
},
"require": {
"php": "^7.1 || ^8.0",
"php": "^7.4 || ^8.0",
"symfony/property-access": "^3.0 || ^4.0 || ^5.0 || ^6.0",
"symfony/validator": "^3.0 || ^4.0 || ^5.0 || ^6.0",
"willdurand/jsonp-callback-validator": "^1.0"
Expand Down
2 changes: 1 addition & 1 deletion src/Converter/CamelCaseToSnakeCaseConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function convert($path)
preg_replace(
'/[A-Z]/u',
'_$0',
$path
$path ?? ''
)
),
'_'
Expand Down
5 changes: 2 additions & 3 deletions src/Encoding/Jsonp.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

class Jsonp implements EncoderInterface
{

protected $jsonEncoder;

protected $callbackValidator;
Expand Down Expand Up @@ -57,10 +56,10 @@ public function encode($data)
$this->jsonEncoder->decode($this->parameter);
} catch (EncodingException $exception) {
$this->parameter = null;
$json = $this->jsonEncoder->encode(array(
$json = $this->jsonEncoder->encode([
'error' => 'invalid_parameters',
'error_description' => 'Passed parameter must be valid JSON string',
));
]);
}
}

Expand Down
5 changes: 0 additions & 5 deletions src/Entity/FollowUpFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@

class FollowUpFilter extends Filter
{
/**
* @var int
*/
protected $offset;

/**
* @var int
*/
Expand Down
24 changes: 15 additions & 9 deletions src/Entity/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

namespace Paysera\Component\Serializer\Entity;

class Result implements \IteratorAggregate, ResultInterface
use ArrayIterator;
use BadMethodCallException;
use IteratorAggregate;
use ReturnTypeWillChange;
use Traversable;

class Result implements IteratorAggregate, ResultInterface
{
/**
* @var int
Expand Down Expand Up @@ -37,8 +43,7 @@ class Result implements \IteratorAggregate, ResultInterface
/**
* @var mixed[]
*/
protected $items;

protected $items = [];

public function __construct(?Filter $filter = null)
{
Expand Down Expand Up @@ -201,14 +206,14 @@ public function addItem($item)
/**
* Try to calculate total result count, in case all results are fetched.
*
* @param $resultCount
* @return null
* @throws \BadMethodCallException
* @param int $resultCount
* @return int|null the calculated total count, or null when it cannot be determined
* @throws BadMethodCallException
*/
public function calculateTotalCount($resultCount)
{
if (!$this->getFilter()) {
throw new \BadMethodCallException('filter must be set before calling this method');
throw new BadMethodCallException('filter must be set before calling this method');
}

if (
Expand All @@ -226,10 +231,11 @@ public function calculateTotalCount($resultCount)
/**
* Retrieve an external iterator
*
* @return \Traversable
* @return Traversable
*/
#[ReturnTypeWillChange]
public function getIterator()
{
return new \ArrayIterator($this->items);
return new ArrayIterator($this->items);
}
}
4 changes: 3 additions & 1 deletion src/Entity/ResultInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Paysera\Component\Serializer\Entity;

interface ResultInterface extends \Traversable
use Traversable;

interface ResultInterface extends Traversable
{
/**
* Gets totalCount
Expand Down
4 changes: 3 additions & 1 deletion src/Exception/EncodingException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Paysera\Component\Serializer\Exception;

class EncodingException extends \Exception
use Exception;

class EncodingException extends Exception
{
}
9 changes: 4 additions & 5 deletions src/Factory/ContextAwareNormalizerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@

use Paysera\Component\Serializer\Filter\FieldsFilter;
use Paysera\Component\Serializer\Filter\FieldsParser;
use Paysera\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Paysera\Component\Serializer\Normalizer\DenormalizerInterface;
use Paysera\Component\Serializer\Normalizer\DistributedNormalizer;
use Paysera\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Paysera\Component\Serializer\Normalizer\NormalizerInterface;

class ContextAwareNormalizerFactory
{

/**
* @var \Paysera\Component\Serializer\Filter\FieldsFilter
* @var FieldsFilter
*/
protected $fieldsFilter;

/**
* @var \Paysera\Component\Serializer\Filter\FieldsParser
* @var FieldsParser
*/
protected $fieldsParser;

Expand All @@ -44,4 +43,4 @@ public function create($normalizer)
$normalizer
);
}
}
}
9 changes: 5 additions & 4 deletions src/Factory/ResponseMapperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Paysera\Component\Serializer\Factory;

use Paysera\Component\Serializer\Normalizer\NormalizerInterface;
use RuntimeException;

class ResponseMapperFactory implements ResponseMapperFactoryInterface
{
Expand All @@ -22,7 +23,7 @@ class ResponseMapperFactory implements ResponseMapperFactoryInterface
public function __construct(NormalizerInterface $defaultMapper)
{
$this->defaultMapper = $defaultMapper;
$this->mappers = array();
$this->mappers = [];
}

/**
Expand All @@ -40,14 +41,14 @@ public function addMapper($key, NormalizerInterface $mapper)
/**
* @param array $options
*
* @throws \RuntimeException
* @throws RuntimeException
* @return NormalizerInterface
*/
public function createResponseMapper(array $options)
{
$key = isset($options[self::MAPPER_OPTION]) ? $options[self::MAPPER_OPTION] : null;
if ($key !== null && !isset($this->mappers[$key])) {
throw new \RuntimeException('Wrong mapper key specified: ' . $key);
throw new RuntimeException('Wrong mapper key specified: ' . $key);
}
if ($key === null) {
foreach ($options as $optionKey => $value) {
Expand All @@ -58,4 +59,4 @@ public function createResponseMapper(array $options)
}
return $key !== null ? $this->mappers[$key] : $this->defaultMapper;
}
}
}
4 changes: 2 additions & 2 deletions src/Filter/FieldsConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function getFieldExtensions($fieldName)
}
return $extensions;
} else {
return $this->defaultsIncluded ? array('*') : array();
return $this->defaultsIncluded ? ['*'] : [];
}
}

Expand All @@ -66,4 +66,4 @@ public function areDefaultsIncluded()
{
return $this->defaultsIncluded;
}
}
}
6 changes: 4 additions & 2 deletions src/Filter/FieldsFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Paysera\Component\Serializer\Filter;

use ArrayObject;

class FieldsFilter
{
/**
Expand Down Expand Up @@ -33,7 +35,7 @@ public function filter($data, ?array $fields = null, array $scope = [])
if ($this->isAssociativeArray($data)) {
$result = $this->filterByConfig($data, $fieldsConfig);
if (is_array($result) && count($result) === 0) {
$result = new \ArrayObject();
$result = new ArrayObject();
}
return $result;
} else {
Expand All @@ -52,7 +54,7 @@ public function filter($data, ?array $fields = null, array $scope = [])
*/
protected function filterByConfig($data, FieldsConfig $fieldsConfig)
{
$result = array();
$result = [];
foreach ($data as $fieldName => $value) {
if ($fieldsConfig->isIncluded($fieldName)) {
if (is_array($value)) {
Expand Down
13 changes: 7 additions & 6 deletions src/Filter/FieldsParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace Paysera\Component\Serializer\Filter;

use InvalidArgumentException;

class FieldsParser
{

/**
* @param null|array $fields
* @param array $scope
Expand All @@ -23,7 +24,7 @@ public function parseFields(?array $fields = null, array $scope = [])
/**
* @param null|array $fields
*
* @throws \InvalidArgumentException
* @throws InvalidArgumentException
* @return FieldsConfig
*/
public function parseUnscopedFields(?array $fields = null)
Expand All @@ -33,15 +34,15 @@ public function parseUnscopedFields(?array $fields = null)
}

$defaultsIncluded = false;
$includedFields = array();
$fieldExtensions = array();
$includedFields = [];
$fieldExtensions = [];

foreach ($fields as $fieldDefinition) {
// todo: take curly braces? see commented test-case for possible usage
foreach (explode(',', $fieldDefinition) as $field) {
$list = explode('.', $field, 2);
if (isset($list[1]) && $list[1] === '') {
throw new \InvalidArgumentException('Invalid field provided, field cannot end with a dot');
throw new InvalidArgumentException('Invalid field provided, field cannot end with a dot');
}
$name = $list[0];
$extension = isset($list[1]) ? $list[1] : null;
Expand All @@ -63,6 +64,6 @@ public function parseUnscopedFields(?array $fields = null)
*/
protected function createWithDefaultsIncluded()
{
return new FieldsConfig(true, array(), array());
return new FieldsConfig(true, [], []);
}
}
Loading