Skip to content

ryanwhitman/php-values

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHP Values

Latest Version on Packagist PHP from Packagist Software License Total Downloads

PHP Values is a tool for creating immutable value objects in PHP. A value object intakes a raw value, transforms it, validates it, and can be used consistently and dependably across your application.

For instance, suppose you need an email address when creating a user. You can write it more traditionally like this:

public function createUser(string $email)
{
    // perform sanitation and validation on email before using
}

But it's more optimal to write it like this:

use RyanWhitman\PhpValues\Email;

public function createUser(Email $email)
{
    // email has already been sanitized and validated and is ready for use
}

Install

You should install the package via composer:

composer require ryanwhitman/php-values

Example

Start by creating a Value class. For instance, a Value class for an email address:

<?php

namespace App\Values;

use RyanWhitman\PhpValues\Value;
use RyanWhitman\PhpValues\Concerns\Stringable;

class Email extends Value
{
    use Stringable;

    protected function transform(string $email): string
    {
        return filter_var($email, FILTER_SANITIZE_EMAIL);
    }

    protected function validate(string $email): bool
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL);
    }
}

Now, you're ready to use the value:

<?php

use App\Values\Email;

// Valid email address
Email::from('[email protected]'); // instance of Email
Email::from('[email protected]')->get(); // [email protected]
Email::getFrom('[email protected]'); // [email protected]
(string) Email::from('[email protected]'); // [email protected]
Email::isValid('[email protected]'); // true

// Valid email address (with imperfections)
Email::getFrom(' email @example.com '); // [email protected]
Email::isValid(' email @example.com '); // true

// Invalid email address
Email::from('non-email'); // throws exception
Email::tryFrom('non-email'); // null
Email::isValid('non-email'); // false

Usage

To create a new Value class, extend the RyanWhitman\PhpValues\Value class. From there, define a transform method (optional) and a validate method (mandatory). Upon instantiation, the transform method receives the raw input and transforms it, as needed. Then, the validate method receives the transformed value and returns true or false. If validation passes, the object is ready for use. If validation passes, InvalidValueException is thrown. Note: 2 try static methods exist that catch the exception and return null.

transform(mixed $value): mixed

The transform method is an optional method called during instantiation. It receives the input value and, when defined, should return a sanitized/transformed version of the value. The transform method is not defined in the base abstract Value class to allow for proper typing in sub-classes.

protected function transform(string $email): string
{
    return filter_var($email, FILTER_SANITIZE_EMAIL);
}

validate(mixed $value): bool

The validate method is called during instantiation. It receives the transformed value and should return true or false. The validate method is not defined in the base abstract Value class to allow for proper typing in sub-classes.

protected function validate(string $email): bool
{
    return filter_var($email, FILTER_VALIDATE_EMAIL);
}

Base Values

Suppose you're creating a Value class for a person's name. You'll likely want to remove all superfluous whitespace. You could, of course, simply call another Value class within your transform method, but you can also define a $baseValues property to automatically run other Value classes:

<?php

namespace App\Values;

use RyanWhitman\PhpValues\SquishedString;
use RyanWhitman\PhpValues\Value;

class Name extends Value
{
    protected array $baseValues = [
        SquishedString::class,
    ];

    // ...
}

Static Methods

from(mixed $value): Value

The from static method will return a Value instance when validation passes and will throw an exception when validation fails.

Email::from('[email protected]'); // instance of Email
Email::from('non-email'); // throws InvalidValueException

getFrom(mixed $value): mixed

The getFrom static method is a shortcut for ::from($value)->get().

Email::getFrom('[email protected]'); // [email protected]
Email::getFrom('non-email'); // throws InvalidValueException

tryFrom(mixed $value): ?Value

The tryFrom static method will return a Value instance when validation passes and null when validation fails.

Email::tryFrom('[email protected]'); // instance of Email
Email::tryFrom('non-email'); // null

tryGetFrom(mixed $value): mixed

The tryGetFrom static method is a shortcut for ::tryFrom($value)->get().

Email::tryGetFrom('[email protected]'); // [email protected]
Email::tryGetFrom('non-email'); // null

isValid(mixed $value): bool

The isValid static method will return true or false.

Email::isValid('[email protected]'); // true
Email::isValid('non-email'); // false

Instance Methods

getOrigValue(): mixed

The getOrigValue method returns the original input value (before transformation).

Email::from('e m [email protected]')->getOrigValue(); // e m [email protected]

get(): mixed

The get method returns the transformed and validated value.

Email::from('e m [email protected]')->get(); // [email protected]

Shortcut Methods

As mentioned above, the getFrom and tryGetFrom static methods are shortcuts for ::from($value)->get() and ::tryFrom($value)->get(), respectively. You may add the ShortcutMethod annotation/attribute to your custom get methods to add the same shortcut capabilities. Shortcut methods must be defined using camelCase and start with get (e.g. getFormatted).

Using a doctrine annotation in PHP 7.4+:

use RyanWhitman\PhpValues\Annotations\ShortcutMethod;

/**
 * @ShortcutMethod
 */
public function getFormatted()
{
    // ...
}

Using an attribute in PHP 8.0+:

use RyanWhitman\PhpValues\Attributes\ShortcutMethod;

#[ShortcutMethod]
public function getFormatted()
{
    // ...
}

After adding the ShortcutMethod annotation/attribute to the getFormatted method, for example, the following will work:

::getFormattedFrom($value)
::tryGetFormattedFrom($value)

Traits

RyanWhitman\PhpValues\Concerns\Stringable

The Stringable trait simply defines the __toString() magic method with (string) $this->get().

Exceptions

PHP Values will throw 1 of 2 exceptions:

RyanWhitman\PhpValues\Exceptions\InvalidValueException will be thrown when either a TypeError occurs (e.g. an array is needed but a string is provided) or when validation fails. This exception is useful as it indicates the raw input is invalid. RyanWhitman\PhpValues\Exceptions\Exception is thrown when something else goes wrong (e.g. a validate method is not defined). Note: The try methods only catch InvalidValueException.

Pre-Built Values

Testing

composer test

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please have a look at License File for more information.