Download the PHP package foorg/moose without Composer
On this page you can find all versions of the php package foorg/moose. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Package moose
Short Description Moose - l[oose] object [m]apper. It allows you to map arbitrary data to objects, trying to coerce values to given types and failing gracefully with a list of validation errors. This is useful for consuming or writing APIs where incoming data can be of invalid format or type.
License MIT
Informations about the package moose
Moose
L[oose] object [M]apper - it maps data on objects, failing only gracefully. Instead of throwing an exception when some piece of data isn't right it will just return to you a stack of collected errors and a partial object.
This is useful for consuming 3d-party APIs or building your own where you need to report all invalid pieces of data.
- Install
- Use
- Extend
Installing
You can add this library to your project with composer require foorg/moose
.
How to use it
The most convenient way of using it is with AnnotationMetadataProvider
.
Suppose we have this kind of API format for sending email messages:
We can map this on objects if we define them with appropriate annotations:
Here's how we can get the object out of json:
There are also decorators for MetadataProvider
that allow for proper caching of
metadata but that's another story.
This library comes with a number of predefined types, here's a list of them:
ArrayField([T: TypeRef])
(if you don't want homogeneous array you can omit theT
parameter)DateField(format)
MapField([K: TypeRef, V: TypeRef]|[V: TypeRef])
ObjectField(classname: string)
BoolField()
FloatField()
IntField()
StringField()
TaggedUnionField(tag: string, map: { tag: string => typeOrClassname: string|TypeRef })
TypeRef
stands for another (nested) annotation of Field
type, e.g.
ArrayField(T=IntField())
(there is no limit on nesting levels)
By the way, types that expect only one parameter (that is ArrayField
,
DateField
, MapField(V)
and ObjectField
) can be instantiated like so:
ArrayField(IntField())
(no name needed for the first parameter)
TaggedUnion
allows you to have a field that can contain any of the
listed types. Here's how to make it work:
This configuration will be able map data of the form:
Caching metadata
There are two independent metadata providers: AnnotationMetadataProvider
and
CacheMetadataProvider
. In order to cache metadata you need to wire them together
either with ProdCacheMetadataProvider
or with InvalidatingAnnotationMetadataProvider
.
They have different behavior in a way that ProdCacheMetadataProvider
will always use
metadata from cache if it's present there (otherwise it will create it and store in cache),
whereas InvalidatingAnnotationMetadataProvider
will always check if cache needs to be
warmed up first. It's natural to use the former in production and the latter in development
mode, although you could use invalidating provider for both of them as stat()
syscalls
are not that expensive.
Add new data types
If you want to add your own data type, perhaps to replace and extend some of the existing or to add a new one, you can do this pretty easily and here's how.
Let's think about a hypothetical situation where we have a json API and there's an
endpoint where in incoming data there's a ids
field and it is a list of IDs
separated with comma, e.g. ids=1,2,3,4
. As you might guess our existing ArrayField
type would expect it to be array
but it is in fact a string.
However, we could create our own type that would handle this case gracefully. Note though
that extending ArrayField
would probably be better in this case but it wouldn't show
all the steps of creating a new type.
We'll start from creating our own annotation class:
Now we will need to create the mapper itself, but we call it coercer because Moose not only maps data but also tries to coerce types to the right ones.
And now we need to add this type to the coercers that we pass to the moose\Mapper
:
Here's how this new annotation can be used in classes: