A PHP 7 value objects helper library.

Overview

valueobjects

Build Status Version

Requirements

Requires PHP >= 7.1

Installation

Through Composer, obviously:

composer require funeralzone/valueobjects

Extensions

This library only deals with fundamental values (scalars). We've also released an extension library which provides a starting point for more complex values.

Our approach

We've written up our philosophy to PHP value objects in our A better way of writing value objects in PHP article.

Single value object

If your VO encapsulates a single value, it's most likely a scalar. We've provided some traits to deal with scalars under:

src/Scalars

Let's say you have a domain value called 'User Email'. You'd create a class which implements the ValueObject interface:

final class UserEmail implements ValueObject {
...

You now need to implement the interface. But because an email can essentially be considered a special kind of string (in this simple case) the StringTrait helper trait can implement most of the interface for you:

final class UserEmail implements ValueObject {

    use StringTrait;
...

In our case, a user's email has other domain logic that we can encapsulate in our VO. User emails have to be a valid email:

...
    public function __construct(string $string)
    {
        Assert::that($string)->email();
        $this->string = $string;
    }
...

You can see an example of how to implement single value objects in the examples directory.

Enums

Enums can be defined easily through use of the EnumTrait. Then, the enum values are simply listed as constants on the class.

final class Fastening implements ValueObject
{
    use EnumTrait;
    
    public const BUTTON = 0;
    public const CLIP = 1;
    public const PIN = 2;
    public const ZIP = 3;
}

When dealing with value object serialisation, the constant names are used. They are case-sensitive. So:

$fastening = Fastening::fromNative('BUTTON');
$fastening->toNative(); // Equals to string: 'BUTTON'

In code, the trait utilises magic methods to create objects based on constant name like so:

$fastening = Fastening::ZIP();
$fastening->toNative(); // Equals 'ZIP'

If your IDE supports code completion and you'd like to use named methods to create enums you can add the following PHPDoc block to your enum class:

/**
 * @method static Fastening BUTTON()
 * @method static Fastening CLIP()
 * @method static Fastening PIN()
 * @method static Fastening ZIP()
 */
final class Fastening implements ValueObject

Composite value objects

A composite value object is a more complex value which is made from other values.

final class Location implements ValueObject
{
    use CompositeTrait;
    
    private $latitude;
    private $longitude;
    
    public function __construct(Latitude $latitude, Longitude $longitude)
    {
        $this->latitude = $latitude;
        $this->longitude = $longitude;
    }
    
    public function getLatitude(): Latitude
    {
        return $this->latitude;
    }
    
    public function getLongitude(): Longitude
    {
        return $this->longitude;
    }
...

A Location is made up of two VOs (latitude, longitude). We've provided a CompositeTrait to easily implement most of the ValueObject interface automatically. It handles toNative serialistation by using reflection to return an array of all the class properties.

The CompositeTrait does not implement fromNative. We leave the construction of your object up to you.

...
    public static function fromNative($native)
    {
        return new static(
            Latitude::fromNative($native['latitude']),
            Longitude::fromNative($native['longitude'])
        );
    }
...

You can see an example of how to implement composite objects in the examples directory.

Nulls, NonNulls and Nullables

This package allows you to deal with nullable value objects.

First create a type of value object.

interface PhoneNumber extends ValueObject
{
}

Implement a non-null version of the value object.

final class NonNullPhoneNumber implements PhoneNumber
{
    use StringTrait;
}

Implement a null version of the value object.

final class NullPhoneNumber implements PhoneNumber
{
    use NullTrait;
}

Implement a nullable version of the value object.

final class NullablePhoneNumber extends Nullable implements PhoneNumber
{
    protected static function nonNullImplementation(): string
    {
        return NonNullPhoneNumber::class;
    }
    
    protected static function nullImplementation(): string
    {
        return NullPhoneNumber::class;
    }
}

This 'nullable' handles automatic creation of either a null or a non-null version of the interface based on the native input. For example:

$phoneNumber = NullablePhoneNumber::fromNative(null);

The $phoneNumber above will automatically use the NullPhoneNumber implementation specified above.

Or:

$phoneNumber = NullablePhoneNumber::fromNative('+44 73715525763');

The $phoneNumber above will automatically use the NonNullPhoneNumber implementation specified above.

Sets of value objects

A set of value objects should implement the Set interface. It's just an extension of the ValueObject interface with a few simple additions.

interface Set extends ValueObject, \IteratorAggregate, \ArrayAccess, \Countable
{
    public function add($set);
    public function remove($set);
    public function contains(ValueObject $value): bool;
    public function toArray(): array;
}
  • add Add values from another set to the current set.
  • remove Remove all the values contained in another set from the current set.
  • contains Returns true if the value exists in the current set.
  • toArray Returns a simple PHP array containing all of the value objects.

The other interfaces that the Set interface extends from (\IteratorAggregate, \ArrayAccess, \Countable) are for accessing the set object as though it was an array.

Non-null sets

The library provides a default implementation of the interface.

final class SetOfLocations extends NonNullSet implements Set
{
    protected function typeToEnforce(): string
    {
        return Location::class;
    }

    public static function valuesShouldBeUnique(): bool
    {
        return true;
    }
}

There are two abstract methods that need to be implemented.

  • typeToEnforce should return a string of the class name of the value object that you want to make a set of.
  • valuesShouldBeUnique should return a boolean representing whether you want to force the set to be unique.

If the set is set to unique, if duplicate values are added to the set (at instantiation or through the add method) the duplicates are filtered out.

Null and nullable sets

Just like standard value objects there are some constructs to help with creating nullable and null sets. See the Nulls, NonNulls and Nullables section for more information.

  • NullableSet The set equivalent of Nullable.
  • NullSetTrait The set equivalent of the NullTrait.

Usage of sets

Iteration, access and counting

// Iteration
$set = new SetOfLocations([$one, $two]);
foreach($set as $value) {
    // TODO: Do something with each value object
}

// Access
$one = $set[0];
$two = $set[1];

//Counting
$count = count($set); // Returns 2

add

Merges another set.

$set = new SetOfLocations([$one, $two]);
$anotherSet = new SetOfLocations([$three]);
$mergedSet = $set->add($anotherSet);
count($mergedSet) // Equals: 3

remove

Removes values from a set by using another set as reference values.

$set = new SetOfLocations([$one, $two, $three]);
$anotherSet = new SetOfLocations([$one]);
$remove = $set->remove($anotherSet);
count($remove) // Equals: 2

contains

Checks whether a set contains a particular value object.

$set = new SetOfLocations([$one, $two, $three]);
$one = new Location(0);
$check = $set->contains($one);
You might also like...
Enable method chaining or fluent expressions for any value and method.

PHP Pipe Operator A (hopefully) temporary solution to implement the pipe operator in PHP. Table of contents Requirements How to install How to use The

Decimal handling as value object instead of plain strings.

Decimal Object Decimal value object for PHP. Background When working with monetary values, normal data types like int or float are not suitable for ex

High-performance, low-memory-footprint, single-file embedded database for key/value storage

LDBA - a fast, pure PHP, key-value database. Information LDBA is a high-performance, low-memory-footprint, single-file embedded database for key/value

Provides JSON pointer as a value object

json-pointer Provides JSON pointer as a value object. Installation Run composer require ergebnis/json-pointer Usage ReferenceToken You can create a Re

LendCash is a cash lending service that lets you take loans against your stocks portfolio value and pay back on a prorated basis.

LendCash is a cash lending service that lets you take loans against your stocks portfolio value and pay back on a prorated basis.

This package implements 0-1 Knapsack Problem algorithm i.e. allows to find the best way to fill a knapsack of a specified volume with items of a certain volume and value.

This package implements "0-1 Knapsack Problem" algorithm i.e. allows to find the best way to fill a knapsack of a specified volume with items of a certain volume and value.

:date: The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects

sabre/vobject The VObject library allows you to easily parse and manipulate iCalendar and vCard objects using PHP. The goal of the VObject library is

Samsui is a factory library for building PHP objects useful for setting up test data in your applications.

#Samsui Samsui is a factory library for building PHP objects useful for setting up test data in your applications. It is mainly inspired by Rosie for

JSONFinder - a library that can find json values in a mixed text or html documents, can filter and search the json tree, and converts php objects to json without 'ext-json' extension.

JSONFinder - a library that can find json values in a mixed text or html documents, can filter and search the json tree, and converts php objects to json without 'ext-json' extension.

Comments
  • funeralzone/valueobjects 0.4.5 Requirement: Requires PHP >= 7.1, but my php version (8.0.1)

    funeralzone/valueobjects 0.4.5 Requirement: Requires PHP >= 7.1, but my php version (8.0.1)

    funeralzone/valueobjects 0.4.5 requires php ^7.1.0 -> your php version (8.0.1) does not satisfy that requirement.

    On Requirements: Requires PHP >= 7.1, shouldn't it be =7.1 PHP version 8.0.1 is >= 7.1, but doesn't work

    opened by mechadragon01 1
  • Quick null nullables

    Quick null nullables

    Added a helper function to nullable to quickly create null backed nullables.

    We've found ourselves doing the following rather frequently: $null = Nullable::fromNative(null);

    Just to be (slightly) quicker, but also to better show intent, this PR introduces the following shorthand: $null = Nullable::null();

    opened by chrisharrison 0
  • Great library

    Great library

    Very nice philosophy, thank you for putting this together. This is the best VO implementation I have found. I see the last commit was 16 months ago. Is it being actively maintained (I do imagine it's a rather stable implementation without much need for revision)?

    opened by neodisco 1
Releases(0.5)
Owner
Funeral Zone
Writing software to help the bereaved.
Funeral Zone
Collection of value objects that represent the types of the PHP type system

sebastian/type Collection of value objects that represent the types of the PHP type system. Installation You can add this library as a local, per-proj

Sebastian Bergmann 1.1k Dec 29, 2022
Parse DSN strings into value objects to make them easier to use, pass around and manipulate

DSN parser Parse DSN strings into value objects to make them easier to use, pass around and manipulate. Install Via Composer composer require nyholm/d

Tobias Nyholm 77 Dec 13, 2022
A bunch of general-purpose value objects you can use in your Laravel application.

Laravel Value Objects A bunch of general-purpose value objects you can use in your Laravel application. The package requires PHP ^8.0 and Laravel ^9.7

Michael Rubél 136 Jan 4, 2023
Deeper is a easy way to compare if 2 objects is equal based on values in these objects. This library is heavily inspired in Golang's reflect.DeepEqual().

Deeper Deeper is a easy way to compare if 2 objects is equal based on values in these objects. This library is heavily inspired in Golang's reflect.De

Joubert RedRat 4 Feb 12, 2022
Immutable value object for IPv4 and IPv6 addresses, including helper methods and Doctrine support.

IP is an immutable value object for (both version 4 and 6) IP addresses. Several helper methods are provided for ranges, broadcast and network address

Darsyn 224 Dec 28, 2022
Creating data transfer objects with the power of php objects. No php attributes, no reflection api, and no other under the hook work.

Super Simple DTO Creating data transfer objects with the power of php objects. No php attributes, no reflection api, and no other under the hook work.

Mohammed Manssour 8 Jun 8, 2023
PHP package to make your objects strict and throw exception when you try to access or set some undefined property in your objects.

?? Yell PHP package to make your objects strict and throw exception when you try to access or set some undefined property in your objects. Requirement

Zeeshan Ahmad 20 Dec 8, 2018
PHP library that helps to map any input into a strongly-typed value object structure.

Valinor • PHP object mapper with strong type support Valinor is a PHP library that helps to map any input into a strongly-typed value object structure

Team CuyZ 873 Jan 7, 2023
Yet another Value Object Library (YAVOL)

Yet Another DDD Library Value object This library is a foundation in order to implement the Value Object pattern. It helps you to introduce some DDD s

YADDDL 3 Nov 17, 2022
Dobren Dragojević 6 Jun 11, 2023