Download the PHP package slepic/value-object without Composer

On this page you can find all versions of the php package slepic/value-object. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package value-object

php-value-object

PHP Value Objects

Requirements

Installation

Introduction

This library aims to provide unification of commonalities of all value objects. Additionally, it provides some features that take advantage of the unified environment:

What is a value object?

Value objects are guards of validity. Once a value object is constructed, it contains valid data. And as long as that object lives, we don't have to validate it again.

Note: For simplicity, I am exposing everything in the examples as public properties which allows modifications. They should really be private with public getters.

What commonalities do value objects have a how we unify them?

How can we take advantage of the unifications?

Unified errors

Since value objects need valid state, they have to check it. And this inherently means that they are doing validations and they have to do it themselves. If we just let value objects throw \InvalidArgumentException and instead we do validations (with client error reporting) beforehand, we are basically doing the validation twice. Once to feed the client with reasonable explanation where he screwed up and once in the value object to make sure it's not constructed from bullocks. And if we are lazy, we omit one or the other (or both in worst case).

Omitting validation outside value objects means that our value objects may throw and we end up with 500 Internal Server Error. Omitting validation inside value objects means that we will never be truly sure that they are valid. Omitting them both is just disaster. Having both is redundant and may lead to de-synchronization between the two.

If our value objects do the validations (which they should anyway) and offer a unified way to describe their expectations and eventual violations of said expectations, they effectively force you to validate your data:

Unification of how value objects represent violations allows applications to incorporate value objects errors into their input validation process.

However, the way this incorporation is done for specific application is outside the scope of the library.

This library attempts to unify the error exception as ViolationExceptionInterface with a getViolations(): array<ViolationInterface> method. A default implementation ViolationException is also provided by the library.

ViolationInterface is a marker interface for violations and each violation class name represents an error code. With possibility to carry additional information exposed as properties/getters. This also allows for error code inheritance and avoids error code conflicts between vendors.

Having an array of violations also gives is the option to report multiple violations at the same time.

A set of implementations is provided by this library, including some violations that describe nested errors of collections.

Unified conversions

Often value objects provide named constructors that allow to construct them from a primitive. And it isn't also uncommon that value objects can convert themselves to a primitive type.

This library provides a set of interfaces that define how conversion from and to primitive types should look like.

In the example below, they are the FromStringConstructableInterface and ToStringConvertibleInterface, defining the public static function fromString(string $value): self and public function __toString(): string methods respectively.

This gives as unified environment. It is sure easier to work with if all value objects that can be constructed from a single string value have the same named constructor for this. And, well, in case of conversion to string, that is already covered by PHP's magic method __toString(), but we also offer interfaces for int, float, etc. that go about the same names like ToIntConvertibleInterface and so on...

And it allows to automatically construct composite value objects using their own class definition. See collections section.

Common value objects

Now, wait a minute! Both first name and surname check the same thing. Let's get rid of that duplication.

We have moved the responsibility for checking the value emptiness to the NonEmptyString class. However we have lost the ability to be specific about which property it is that is empty.

That is however responsibility of the caller of the constructor, because he is now creating those NonEmptyString value objects.

Let's see such a caller in the form of a factory that creates the object from primitive strings. It now manages the error codes and messages and overrides the defaults, while using the same codes (violation classes).

But we have also added a new type that is now a guarantee of non empty string.

And you know, if you don't care that much for all the violations, you do just this:

Anyway, we can now avoid some checks on other places.

This effectively forces the caller to validate the input at some point, while leaving the function to care only about its logic.

This library provides a set of base value objects that encapsulate some common restrictions we have on our primitive data types.

Note: ViolationInterface implementations should only describe the error, what it is that was violated. If consumers want to know everything that could have been violated, they have to reach for the value object type itself.

Immutable Traits

This package offers two traits that support immutability of value objects.

ImmutableObjectTrait - disables implementation of magic __set and __unset methods.

ImmutableArrayAccessTrait - disables implementation of ArrayAccess::offsetSet and ArrayAccess::offsetUnset.

These traits are used by all the base value objects in this package. And you are encouraged to use them on your value objects as well.

Nevertheless you are still free to create public properties. There's actually one exception in this package that relies on public properties - DataTransferObject class. But other than that, we discourage you from using them, although it is often a bit less writing if you do.

You are also always free to modify your objects using reflection, etc. So to be truly immutable is basically impossible in PHP. But we try as much as we can :)

Base Value Objects

Often we need to wrap primitive values and enforce some kind of limitation, like a limit on a string length, allow only subset of all characters in a string, or limit a maximum value of a number.

Simple implementations of scalar objects with these common restrictions can be found in the package.

Strings

Integers

Floats

Enums

We consider several axis for enums

Each aspect has cons and pros. Currently only strong string enums are implemented.

Collections

The package supports 3 main types of collections

DataTransferObject

Note: If you sometimes need to construct the object not from array, but directly from separate variables, consider not extending DataTransferObject, implement your object, with own constructor and use FromArrayConstructor helper class to simplify the creation from array.

ArrayList

ArrayMap

FromArrayConstructor

This is not a value object, it is a static helper class which simplifies construction of objects from associative array of named parameters for their class constructor.

This helper also supports upcasting and downcasting. See upcasting/downcasting sections.

Constructor parameters must have a default value to become optional in the input array. The parameters also must have a typehint.

By default the method reports any unexpected properties of the input through UnknownProperty violation. This can be turned off by passing true as the 3rd parameter $ignoreExtraProperties.

Basically, this method throws the same violations as DataTransferObject.

The combineWithArray method expects that non-instance properties exists with the same name as each constructor parameter, that is not passed as the $data argument to the combineWithArray method. These properties must have a compatible type with the respective constructor parameter. Calling the combineWithArray method on objects that don't obey this rule, will result in a LogicException and no violations will be reported.

The extractConstructorArguments method expects non-instance properties exist with the same name as each constructor parameter, These properties must have a compatible type with the respective constructor parameter. Calling the extractConstructorArguments method on objects that don't obey this rule, will result in a LogicException and no violations will be reported.

Note: writing these value objects will become even easier with PHP8's constructor promotion. If you only need your object constructed from array and the constructor itself seems like a burden, you should consider DataTransferObject instead.

DataStructure

This is basically a wrapper for FromArrayConstructor capabilities, which also provides from and to array upcasting/downcasting capabilities. This is the most solid base for an immutable data structure, if you are willing to write the constructor with all its properties. If you are not willing, use DataTransferObject. However with PHP8's constructor promotion feature, this will become equally simple and the DataStructure class will become the choice #1.

Standards

Additionaly we provide a set of standard value objects for common things, like email, etc. But this sections is currently not ready and in future this may probably be in a separate package.

Upcasting

Whenever a collection expects a value object type and it receives a primitive type, it will look for the appropriate upcasting interface on the target value object class. If it exists, it will automatically construct the value object using the interface.

Existing upcasting interfaces are:

Downcasting

Whenever a collection expects a primitive type and it receives an object, it will look for the appropriate downcasting interface on the value. If it exists it will be used to obtain the primitive value.

Existing downcasting interface are:

FAQ

Is this only usable for validation

No. That's only a side effect that it allows to enhance and integrate with your validation system.

What other use cases are there.

This is basically for any use case where you would use a value object. It just helps you write them in unified way and simplifies some of its concerns.

How about contextual validation? Some field must be an email if another field has a specific value?

That is up to the constructor of the value object. Such a rule cannot be attributed to either of the fields alone. It's absolutely fine to define your own violation class for that and eventually reuse it in multiple value objects.

How about nested validation rules? A client (user/api consumer etc) is sending data to your app and it gets back some errors? How do I communicate back "hey, addresses[5].state is not a valid state"?

The communication of invalid state to the client is under control of your application. You can take advantage on unified violations environment, but you still have to be aware of what kinds of violations your value objects throw and represent each of them accordingly. Although violations are represented as classes, they really are just simple error codes with additional features leveraging the PHP class system. The violations from Collections namespace should make it easy enough to create nested violations for nested value objects. See the code of the collections to see how they are used. And you can also check their tests to see how we check for what happened in the nested violations tree.

How about custom validation messages?

Validation messages provided by ViolationInterface::getMessage() are not meant to be communicated to the client directly. They represent an immediately readable explanation of the violation for a developer. But if the violations are to be communicated to a general user, the messages should be generated within your application's validation system, based on the error codes and eventually other violation properties.

You can use the default messages probably only on API where devs are the only ones who is going to read them.

Chances are though, that in future the ViolationInterface::getMessage() method will be removed entirely.

Some component that simplify this task of integrating the violations into validation systems may be created in future. At this point this is out of the scope of the library, and it would probably become a separate package anyway.

How about validation that requires dependencies (eg: a database connection)?

It is of course possible to throw the unified ViolationExceptionInterface from any factory you want. But this cannot happen within the automatic upcasting, since it happens through static named constructors. But there is no problem passing an already created value object to an automatically constructed value object from this package. And that makes it irrelevant whether the passed-in value object needed database to be created or not.

Similar projects and inspiration

Thank you, guys!


All versions of value-object with dependencies

PHP Build Version
Package Version
Requires php Version >=7.4
ext-json Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package slepic/value-object contains the following files

Loading the files please wait ....