ryanwhitman / php-values
PHP Values
Installs: 415
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/ryanwhitman/php-values
Requires
- php: >=7.4 <8.5
- doctrine/annotations: ^1|^2
Requires (Dev)
- filp/whoops: ^2.14
- oyova/php-cs-fixer: ^1.5
- pestphp/pest: ^1.22
- symfony/var-dumper: ^5.4
README
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@example.com'); // instance of Email Email::from('email@example.com')->get(); // email@example.com Email::getFrom('email@example.com'); // email@example.com (string) Email::from('email@example.com'); // email@example.com Email::isValid('email@example.com'); // true // Valid email address (with imperfections) Email::getFrom(' email @example.com '); // email@example.com 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@example.com'); // 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@example.com'); // email@example.com 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@example.com'); // 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@example.com'); // email@example.com Email::tryGetFrom('non-email'); // null
isValid(mixed $value): bool
The isValid static method will return true or false.
Email::isValid('email@example.com'); // true Email::isValid('non-email'); // false
Instance Methods
getOrigValue(): mixed
The getOrigValue method returns the original input value (before transformation).
Email::from('e m ail@example.com')->getOrigValue(); // e m ail@example.com
get(): mixed
The get method returns the transformed and validated value.
Email::from('e m ail@example.com')->get(); // email@example.com
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 ryanawhitman@gmail.com instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please have a look at License File for more information.