Releases: FireMidge/value-objects
Release list
Version 2.7: Generic classes (& more). PHP 8.4-tested
Breaking changes
next()andprevious()onIsCollectionTypeno longer return a value.- This is because of
\Iteratorrequiringnextto returnvoid, and it makes sense fornextandpreviousto function in the same way.
- This is because of
ConversionErrornow extends from\ValueError(previously\RuntimeException)
Features
-
Added default classes to be able to use some of the traits instantly without having to create an empty new class each time. The classes added are:
\FireMidge\ValueObject\Generic\AnyCollection\FireMidge\ValueObject\Generic\AnyFloat\FireMidge\ValueObject\Generic\AnyInteger\FireMidge\ValueObject\Generic\AnyString- All of the above classes implement
\JsonSerializable, andAnyCollectionalso implements the\Iteratorinterface.
-
Added default
PercentageandEmailclasses\FireMidge\ValueObject\Generic\Percentage\FireMidge\ValueObject\Generic\Email
-
New methods on
IsCollectionType:mergewithMergedpoppopMultiplesplitshufflewithReversedOrder
-
jsonSerializehas been implemented for all types, to aid easy serialisation.- In order for automatic serialisation to happen when
json_encodeis called, the class using these traits has to implement theJsonSerializableinterface. - The new generic classes all implement it already.
- In order for automatic serialisation to happen when
Improvements
- Added Psalm annotations in the collection type.
- This allows for better IDE-internal type hints for methods like
toArray(),first(),last()etc. - Usage is showcased in
README.md
- This allows for better IDE-internal type hints for methods like
- More specific error messages for adding or subtracting a value from a float or integer type beyond allowed min/max values.
- Option to return
$reasonsfrom aConversionError InvalidValuerenders different types better, e.g. non-strings are no longer wrapped in double quotes- Library is tested against PHP 8.4. Worked without changes to the code.
- Upgraded from PhpUnit 9 to 11.5 and upgraded Infection to 29.0.
- Changed all docblock annotations to attributes
- Infection's output is vastly improved, removing the vast majority of false positives. MSI has changed from 97% to 99%, Mutation Code Coverage from 98% to 99% and Covered Code MSI from 98% to 100%.
Version 2.6: New 'IsClassArrayEnumType'
Feature: Added new type IsClassArrayEnumType, which is a convenience type between ArrayEnumType and ClassCollectionType.
It's used for collections of instances which in turn are enum types, i.e. there is a finite list of valid values. It also offers an easy way to create a new collection holding all valid variations of the underlying enum type (withAll()).
Feature: Added methods to navigate through the values of IsCollectionType with current, previous, next, first and last. This is, by extension, also available to instances using the IsClassCollectionType, IsArrayEnumType, IsClassArrayEnumType and all other related traits. Unlike the equivalent built-in PHP methods, these new methods return null for non-existing elements instead of false.
Dev: Improved @covers annotations and re-imported certain traits to improve accuracy of code coverage reports. Added tests for all new functionality as well as addressed all true positives in the Infection log. MSI improved from 94% to 97% and CCM from 95% to 98%.
Version 2.5: New convenience methods
B/C-Breaking Change: isClassCollectionType::className() is now a static abstract method. This means all existing classes using this trait will need to change it from protected to protected static. No further changes should be necessary.
As a static, it can be used for a wider range of useful convenience methods, like the new fromRawArray.
Feature: IsClassCollectionType now has a fromRawArray method, which allows creating a new array not from instances of the required class, but from raw values which are then automatically converted into the required class. A custom conversion callback can be provided. In order to globally (for that particular class) override the conversion of raw values into target class instances, you can override the protected static method convertFromRaw(mixed $value) : object.
Feature: IsCollectionType now has find and findIndex methods, which allows returning a specific element (or index, respectively) based on a custom callback. This means it's no longer needed to convert the class back to an array for the sake of finding a specific element.
Feature: isEqualTo and isNotEqualTo have been added to IsStringEnumType, IsStringType, IsIntType, IsIntEnumType and IsFloatType, to be consistent with other traits. ConversionError has been introduced, which is thrown when attempting to perform a loose comparison with a value that cannot be converted to the target type.
Feature: Methods for mathematical operations (add, subtract) and comparisons (isGreaterThan, isGreaterThanOrEqualTo, isLessThan, isLessThanOrEqualTo have been added to IsFloatType and IsIntType.
Feature: IsFloatType now has fromString, fromStringOrNull, fromNumber, fromNumberOrNull.
Feature: IsIntEnumType now has a fromString, fromStringOrNull
Feature: isIntType now has fromStringOrNull (besides the pre-existing fromString) in order to make it consistent with other traits.
Feature: IsIntEnumType now implements the magic __toString method, which aids with comparisons and rendering.
Dev: Tests to cover all of the above have been added. Some additional tests to improve pre-existing ones have been added.
Dev: Every single mutant in the infection.log has been checked - they are all false positives. Several came back as escaped when in fact, the same manual mutation causes tests to fail. The @Covers annotation is correct. It may be a bug in how multi-layer trait inheritance is perceived as covered by Infection. MSI has fallen from 95% to 94% and Covered Code MSI has fallen from 97% to 95% - however, there is nothing that can be done to improve it.
Version 2.4: Strict checks
What's changed?
Change: isEqualTo and isNotEqualTo on IsIntStringMapType default to using a strict check, which means the item to compare it to must be of the same class. If you do not want a strict check to happen, you can continue to pass false for the $strictCheck parameter.
Change: isEqualTo and isNotEqualTo on IsCollectionType (which affects all array types) have a new $strictCheck parameter, defaulting to true. When it is true, the item to compare to must be of the same class. If you do not want a strict check to happen, you can pass false for the $strictCheck parameter.
It is best practice to be as strict as possible with checks to avoid comparing values you did not mean to compare, and encounter unexpected behaviour as a result.
Version 2.3: New methods
What's new?
Feature: Added isEqualTo and isNotEqualTo to IsIntStringMapType.
Overall Mutation Code Coverage has risen from 97% to 98%. No value has decreased.
Feature: Added withValues, withoutValues and tryWithoutValues to IsCollectionType, allowing to add/remove multiple values with a single method call. MSI has risen from 94% to 95% and Covered Code MSI from 96% to 97%.
Version 2.2
What's New?
Feature: It is now possible to also transform values in IsStringEnumType before validating.
Feature: There is a new fromString method on IsIntType.
Other
Code coverage has been improved and is now at 100% for methods, lines and classes/traits. Mutation score has also been improved from an official 28% (which was not accurate) to 94% MSI, 97% Mutation Code Coverage and 96% Covered Code MSI, containing false positives.

Dev: Instead of using method-based @Covers annotations, we now have class-based @Covers annotations, which is working SO much better. Now the Infection log and coverage reports are far more accurate.
Dev: Added more tests, to bring unit test coverage up to 100%.
Dev: Throwing LogicException when trying to validate the length of a string but passing a higher $minNumber than $maxNumber.
Version 2.1: Added IsClassCollectionType and more
What's new?
Feature: Added the following methods to all the array types (IsArrayEnumType, IsCollectionType, IsIntArrayEnumType, IsStringArrayEnumType, IsClassCollectionType):
count: Returns the number of elements inside the array value object.isEmpty: Whether the value object contains any elements.isNotEmpty: The opposite ofisEmpty.isEqualTo: Whether the value object's elements are equal to the argument. The argument can be another class (with atoArraymethod), an array, or an object with public properties.isNotEqualTo: The opposite ofisEqualTo.empty: A factory method to create a new instance with no elements.
Feature: Added a new value type: IsClassCollectionType.
This adds on to IsCollectionType and makes it easier to create a collection holding an array of objects. It validates whether the items are of a specific class. By default, it does not allow duplicate values, however this can be overridden.
Feature: Added a small helper trait CanBeConvertedToStringArray, which can convert an array type into an array of scalar string values. Useful when using IsClassCollectionType with a class implementing the __toString method.
What's changed?
Feature: Adding duplicate values can now be ignored, by overriding the protected static function ignoreDuplicateValues() : bool method and returning true. To be backwards-compatible, it returns false by default.
When this method returns true, then any duplicate values will be ignored and simply not added to the collection; without throwing an exception.
Dev: Separate exception for duplicate values: DuplicateValue.
It is backwards compatible as it extends from InvalidValue, but it does now allow developers to catch this exception separately.
Version 2.0: Upgrade to PHP 8.1
What's new?
Only the PHP 8.1 upgrade. If you don't yet have PHP 8.1, you can continue to use v1.1.
The upgrade means that return types could be changed from self to static, and type hints for different types of numeric values, e.g. float|int $value.
Version 1.1
What's new?
These following types have been added:
IsArrayEnumTypeIsFloatTypeIsIntArrayEnumTypeIsIntStringMapTypeIsIntTypeIsStringArrayEnumTypeIsStringTypeIsEmailTypeIsCollectionType
What's changed?
There is now a fromStringOrNull method on IsStringEnumType, which allows passing a null value. This does not create a new instance but simply returns null back. This is useful for when you don't know whether a value is null but consider it valid.
Likewise, there is a fromIntOrNull method on IsIntEnumType.
The abstract all() method is now static.
Other
All types have been thoroughly covered by unit tests, which can now be run using the provided Docker image.
Infection (a mutation testing tool) has also been installed, been run, and the log checked for any true positives.
Version 1.0
Feature: Basic IsIntEnumType and IsStringEnumType
Provides basic value objects:
IsIntEnumType represents a single integer value, which must be one of a list of allowed values.
IsStringEnumType represents a single string value, which must be one of a list of allowed values.