PHP code example of firemidge / value-objects

1. Go to this page and download the library: Download firemidge/value-objects library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

firemidge / value-objects example snippets


class Season
{
    use IsStringEnumType;

    public const SPRING = 'spring';
    public const SUMMER = 'summer';
    public const AUTUMN = 'autumn';
    public const WINTER = 'winter';

    public static function all() : array
    {
        return [
            self::SPRING,
            self::SUMMER,
            self::AUTUMN,
            self::WINTER,
        ];
    }
}

$spring = Season::fromString(Season::SPRING);

class Status
{
    use IsIntEnumType;
    
    public const INFORMATION  = 1;
    public const SUCCESS      = 2;
    public const REDIRECTION  = 3;
    public const CLIENT_ERROR = 4;
    public const SERVER_ERROR = 5;

    public static function all() : array
    {
        return [
            self::INFORMATION,
            self::SUCCESS,
            self::REDIRECTION,
            self::CLIENT_ERROR,
            self::SERVER_ERROR,
        ];
    }
}

$success = Status::fromInt(Status::SUCCESS);

class Email
{
    use IsEmailType;
}

$email = Email::fromString('[email protected]');

class ProductName
{
    use IsStringType;

    protected function transform(string $value) : string
    {
        return $this->trimAndCapitalise($value);
    }

    protected function validate(string $value) : void
    {
        $this->validateLength($value, 2, 50);
    }
}

// $productName will be 'Orange juice'
$productName = ProductName::fromString('  orange juice');

class Percentage
{
    use IsIntType;

    protected static function minValidValue() : ?int
    {
        return 0;
    }

    protected static function maxValidValue() : ?int
    {
        return 100;
    }
}

class Balance
{
    use IsIntType;

    protected static function minValidValue() : ?int
    {
        return null;
    }
}

class Investment
{
    use IsIntType;

    protected static function minValidValue() : ?int
    {
        return 5;
    }
    
    // It is not necessary to add this in as this is the default.
    protected static function maxValidValue() : ?int
    {
        return null;
    }
}

class OddIntType
{
    use IsIntType;

    protected function validate(int $value) : void
    {
        if ($value % 2 === 0) {
            throw new InvalidValue(sprintf('Only odd values allowed. Value provided: %d', $value));
        }
    }
}

$percentage = Percentage::fromInt(78);

class Percentage
{
    use IsFloatType;

    protected static function minValidValue() : ?float
    {
        return 0;
    }

    protected static function maxValidValue() : ?float
    {
        return 100;
    }
    
    protected function transform(float $value) : float
    {
        return round($value, 2);
    }
}

// $percentage will be 78.58
$percentage = Percentage::fromFloat(78.578);

class Season
{
    use IsIntStringMapType;

    protected static function provideMap() : array
    {
        return [
            1 => 'spring',
            2 => 'summer',
            3 => 'autumn',
            4 => 'winter',
        ];
    }
}

// Returns 'summer'
$label = (Season::fromInt(2))->toString();

// Returns 4
$intValue = (Season::fromString('winter'))->toInt();

class Statuses
{
    use IsIntArrayEnumType;
    
    public const INFORMATION  = 1;
    public const SUCCESS      = 2;
    public const REDIRECTION  = 3;
    public const CLIENT_ERROR = 4;
    public const SERVER_ERROR = 5;

    public static function all() : array
    {
        return [
            self::INFORMATION,
            self::SUCCESS,
            self::REDIRECTION,
            self::CLIENT_ERROR,
            self::SERVER_ERROR,
        ];
    }
    
    protected static function areValuesUnique() : bool
    {
        return true;
    }
}

$statusesToInclude = Statuses::fromArray([Statuses::INFORMATION, Statuses::SUCCESS]);
$allStatuses       = Statuses::withAll();

$statuses = (Statuses::fromArray([]))
    ->withValue(Statuses::SUCCESS)
    ->withValue(Statuses::SERVER_ERROR)
    ->withoutValue(Statuses::SUCCESS);
    
// The difference between tryWithoutValue and withoutValue is that the try method
// will throw an exception if you are trying to remove a value that did not previously
// exist, whereas withoutValue will simply ignore it.
$statusesWithoutSuccess = $statuses->tryWithoutValue(Statuses::SUCCESS);

$containsSuccess = $statusesToInclude->contains(Statuses::SUCCESS);

class UserFieldList
{
    use IsStringArrayEnumType;
    
    public const NAME        = 'name';
    public const EMAIL       = 'email';
    public const STATUS      = 'status';
    public const FRIEND_LIST = 'friendList';

    protected static function all() : array
    {
        return [
            self::NAME,
            self::EMAIL,
            self::STATUS,
            self::FRIEND_LIST,
        ];
    }
}

$fields = $fieldsFromRequest === null
    ? UserFieldList::withAll()
    : UserFieldList::fromArray($fieldsFromRequest);

$fields    = UserFieldList::fromArray([UserFieldList::NAME, UserFieldList::EMAIL]);
$allFields = UserFieldList::withAll();

$fields = (UserFieldList::fromArray([]))
    ->withValue(UserFieldList::FRIEND_LIST)
    ->withValue(UserFieldList::STATUS)
    ->withoutValue(Statuses::FRIEND_LIST);

$containsFriendList = $statusesToInclude->contains(UserFieldList::FRIEND_LIST);

class Sources
{
    use IsClassArrayEnumType;

    protected static function className() : string
    {
        return Source::class;
    }
}

$source = Source::fromString('invitation');

$sources = Sources::empty();
$sources = $sources->withValue($source);

$sources = Sources::withAll(); // $sources now holds an array with ALL possible Source values.

// Compare the first element that was added to $sources:
$sources->first()->isEqualTo(Source::invitation());

// Find a specific value. Returns `null` if the element does not exist in $sources.
$sourceOrNull = $sources->find(fn(Source $src) => $src->isEqualTo(Source::invitation()));

// You can also perform a pre-check whether a specific value exists in the instance of `IsClassArrayEnumType`:
$containsInvitation = $sources->contains(Source::invitation());

class Sources
{
    // Other code here...
    
    /**
     * This method is linked to ignoreDuplicateValues() - therefore, it is important what both of them do 
     * in order to determine the eventual behaviour.
     * 
     * Returning `true` here causes a `DuplicateValue` exception to be thrown when duplicate values are added,
     * either via `fromArray` or `withValue` - UNLESS you also return `true` from `ignoreDuplicateValues()`.
     * 
     * Returning `false` here and from `ignoreDuplicateValues()` means the same values can be 
     * added multiple times.
     * 
     * Default: Returns `false` unless overridden.
     */
    protected static function areValuesUnique() : bool
    {
        return true;
    }
    
    /**
     * Returning `true` here means that when something attempts to add the same value to an instance 
     * more than once, any duplicate values will be silently ignored (no exceptions thrown) - this 
     * is the behaviour regardless of what `areValuesUnique` returns.
     * 
     * Default: Returns `false` unless overridden.
     */
    protected static function ignoreDuplicateValues() : bool
    {
        return true;
    }
}


$sources = Sources::fromRawArray([
    'invitation',
    'promotion',
    'reference',
]);

$months = CustomEnumArray::fromRawArray([
    'January',
    'May',
    'July',
], fn($v) => CustomClass::fromMonth($v)));

class CustomEnumArray
{
    use IsClassCollectionType {
        IsClassCollectionType::convertFromRaw as private _convertFromRaw;
    }

    protected static function className() : string
    {
        return CustomClass::class;
    }

    protected static function convertFromRaw(mixed $value) : object
    {
        try {
            return static::_convertFromRaw($value);
        } catch (ConversionError) {
            return CustomClass::fromMonth($value);
        }
    }
}

$months = Months::fromArray([
    Month::fromString('December'),
    Month::fromString('August'),
    Month::fromString('October'),
]);

// Alternative way of instantiating the enum collection, if the values
// passed can be converted to the target class.
$months = Months::fromRawArray([
    'December',
    'August',
    'October',
];

// Returns 3
$numberOfMonths = $months->count();

// Returns `true`, although strings are passed, as long as `Month` 
// implements the `__toString` method (e.g. via the trait `IsStringType`).
$emailsMatch = $emails->isEqualTo([
   'December',
   'August',
   'October',
]);

class Sources
{
    // Other code here...
    
    /**
     * This method is linked to ignoreDuplicateValues() - therefore, it is important what both of them do 
     * in order to determine the eventual behaviour.
     * 
     * Returning `true` here causes a `DuplicateValue` exception to be thrown when duplicate values are added,
     * either via `fromArray` or `withValue` - UNLESS you also return `true` from `ignoreDuplicateValues()`.
     * 
     * Returning `false` here and from `ignoreDuplicateValues()` means the same values can be 
     * added multiple times.
     * 
     * Default: Returns `false` unless overridden.
     */
    protected static function areValuesUnique() : bool
    {
        return true;
    }
    
    /**
     * Returning `true` here means that when something attempts to add the same value to an instance 
     * more than once, any duplicate values will be silently ignored (no exceptions thrown) - this 
     * is the behaviour regardless of what `areValuesUnique` returns.
     * 
     * Default: Returns `false` unless overridden.
     */
    protected static function ignoreDuplicateValues() : bool
    {
        return true;
    }
}


/**
 * @method static withValue(Status $addedValue)
 * @method static tryWithoutValue(Status $value)
 * @method static contains(Status $value)
 */
class StatusList
{
    use IsArrayEnumType;

    protected static function all() : array
    {
        return array_map(function($value) {
            return Status::fromInt($value);
        }, Status::all());
    }

    protected function validateEach(mixed $value) : void
    {
        if (! is_object($value) || (! $value instanceof Status)) {
            throw InvalidValue::notInstanceOf($value, Status::class);
        }
    }

    protected static function areValuesUnique() : bool
    {
        return true;
    }
    
    protected static function ignoreDuplicateValues() : bool
    {
        return true;
    }
}

$statuses    = StatusList::fromArray([Status::SUCCESS, Status::REDIRECTION]);
$allStatuses = StatusList::withAll();

// $duplicateStatusesIgnored will only contain Status::SUCCESS once.
// [ Status::SUCCESS, Status::REDIRECTION ]
// This is because of `ignoreDuplicateValues` returning true.
$duplicateStatusesIgnored = StatusList::fromArray([
    Status::SUCCESS, 
    Status::REDIRECTION,
    Status::SUCCESS,
])

// $newStatuses will only contain one instance of Status::REDIRECTION.
// This is because of `ignoreDuplicateValues` returning true.
$newStatuses = $statuses->withValue(Status::REDIRECTION);

/**
 * @method static withValue(Email $addedValue)
 * @method static tryWithoutValue(Email $value)
 * @method static contains(Email $value)
 */
class EmailCollection
{
    use IsClassCollectionType, CanBeConvertedToStringArray;

    protected static function className() : string
    {
        return Email::class;
    }
}

$emails = EmailCollection::fromRawArray([
    '[email protected]',
    '[email protected]',
    '[email protected]',
]);

$emails = CustomCollection::fromRawArray([
    '[email protected]',
    '[email protected]',
    '[email protected]',
], fn($v) => CustomClass::fromDomain(substr($v, strrpos($v, '.') + 1)));

class CustomCollection
{
    use IsClassCollectionType {
        IsClassCollectionType::convertFromRaw as private _convertFromRaw;
    }

    protected static function className() : string
    {
        return CustomClass::class;
    }

    protected static function convertFromRaw(mixed $value) : object
    {
        try {
            return static::_convertFromRaw($value);
        } catch (ConversionError) {
            return CustomClass::fromDomain(substr($value, strrpos($value, '.')+1));
        }
    }
}

$emails = EmailCollection::fromArray([
    Email::fromString('[email protected]'),
    Email::fromString('[email protected]'),
    Email::fromString('[email protected]'),
]);

// Alternative way of instantiating the collection, if the values
// passed can be converted to the target class.
$emails = EmailCollection::fromRawArray([
    '[email protected]',
    '[email protected]',
    '[email protected]',
];

// Returns ['[email protected]', '[email protected]', '[email protected]']
// This method is provided by the trait `CanBeConvertedToStringArray`
$emailsAsStrings = $emails->toStringArray();

// Returns 3
$numberOfEmails = $emails->count();

// Returns `true`, even though strings are passed. This is because `Email` 
// implements the `__toString` method (via the trait `IsStringType`).
$emailsMatch = $emails->isEqualTo([
   '[email protected]',
    '[email protected]',
    '[email protected]',
]);

/**
 * @method static withValue(string $addedValue)
 * @method static tryWithoutValue(string $value)
 * @method static contains(string $value)
 */
class ProductNameCollection
{
    use IsCollectionType;
    use CanTransformStrings;

    protected function validateEach(mixed $value) : void
    {
        if (! is_string($value)) {
            throw InvalidValue::invalidType($value, 'string');
        }
    }

    /**
    * @param mixed $value
    * @return mixed
     */
    protected function transformEach($value)
    {
        if (! is_string($value)) {
            return $value;
        }
    
        return $this->trimAndCapitalise($value);
    }
}

// $productNames will be an instance of ProductNameCollection
// with these values: [ 'Orange juice', 'Soap', 'Shampoo' ]
$productNames = ProductNameCollection::fromArray([
    '  orange juice',
    'soap ',
    'SHAMPOO',
]);