Skip to content
A set of PHP Value Objects to manage composite values
Branch: master
Clone or download
Latest commit 5ef646e Apr 8, 2019

README.md

Latest Stable Version Build Status Total Downloads License Code Climate Test Coverage Issue Count SensioLabsInsight

PHP Value Objects

A set of PHP Value Objects to manage simple and composite values.

It supports SimpleValueObjects and ComplexValueObjects.

Complex value objects are hydrated passing an array. If a key of the array isn't recognized as property of the object it is added to the $otherData array so it isn't lost.

Some of those value objects support also the persistence in Doctrine providing custom mapping types (See below).

What are Value Objects

Value Objects are PHP objects that represent and manage simple or complex values. Once set, the value object cannot be modified without changing its identity.

Simple value objects represent a simple value, like an email. Complex value objects represent complex values, that, in order to really represent a value, need more than one value, like a price that needs an amount and a currency to be understandable and have a sense.

PHP supports only one value object: the DateTime object.

This library gives support for other kind of values, differentiating them between complex and simple.

To better understand the concepts behind the value objects, you can read this post.

Install PHPValueObjects via Composer

$ composer require serendipity_hq/php_value_objects

or, in your composer.json

"require": {
  "serendipity_hq/php_value_objects": "~2"
}

This library follows the http://semver.org/ versioning conventions.

Requirements

Available Value Objects

Currently, this library supports the following Value Objects:

Supported Doctrine's Custom Mapping Types

  • CurrencyType
  • EmailType
  • MoneyType
  • UriType

Supported Doctrine's Embeddables

  • Address

Supported Symfony Form Types

  • Address

To use them with Symfony

# Doctrine Configuration
doctrine:
    dbal:
        ...
        types:
            email: SerendipityHQ\Component\ValueObjects\Email\Persistence\EmailType
            money: SerendipityHQ\Component\ValueObjects\Money\Persistence\MoneyType

    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        auto_mapping: true
        mappings:
            mapping_name:
                mapping: true
                type: annotation
                dir: "%kernel.root_dir%/../vendor/serendipity_hq/php_value_objects/src"
                alias: Address
                prefix: SerendipityHQ\Component\ValueObjects
                is_bundle: false

To use the Doctrine's custom mapping types, you have to manually register them.

If you are using Symfony, read Registering custom Mapping Types

To use the form types, in services.yml add:

address_type:
   class: SerendipityHQ\Component\ValueObjects\Address\Bridge\Symfony\Form\Type\AddressType
   tags:
      -  { name: form.type }

Then in your form type:

class YourCustomType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ...
            ->add('address', AddressType::class, ['data_class' => AddressEmbeddable::class])
            ...
    }
}

Note the use of AddressEmbeddable insetead of simply Address: AddressEmbeddable has public methods set as public and also if this way the immutability is lost, this is the only way to use it with Symfony's Forms as they are not able to populate the entity if it hasn't public setters.

To translate the form types, copy the translation files from Address/Resources/translations in AppBundle/Resources/translations and in Twig render the form in this way:

<div class="form-group">
    {{ form_errors(form.address.countryCode) }}
    {{ form_label(form.address.countryCode, 'address.form.country_code.label'|trans({}, 'address')) }}
    {{ form_widget(form.address.countryCode, {'attr': {'class': 'form-control input-sm'}}) }}
</div>
<div class="form-group">
    {{ form_errors(form.address.administrativeArea) }}
    {{ form_label(form.address.administrativeArea, 'company.form.address.administrative_area.label'|trans({}, 'address')) }}
    {{ form_widget(form.address.administrativeArea, {'attr': {'class': 'form-control input-sm'}}) }}
</div>
<div class="form-group">
    {{ form_errors(form.address.locality) }}
    {{ form_label(form.address.locality, 'company.form.address.city.label'|trans({}, 'address')) }}
    {{ form_widget(form.address.locality, {'attr': {'class': 'form-control input-sm'}}) }}
</div>
<div class="form-group">
    {{ form_errors(form.address.dependentLocality) }}
    {{ form_label(form.address.dependentLocality, 'company.form.address.dependent_locality.label'|trans({}, 'address')) }}
    {{ form_widget(form.address.dependentLocality, {'attr': {'class': 'form-control input-sm'}}) }}
</div>
<div class="form-group">
    {{ form_errors(form.address.postalCode) }}
    {{ form_label(form.address.postalCode, 'company.form.address.postal_code.label'|trans({}, 'address')) }}
    {{ form_widget(form.address.postalCode, {'attr': {'class': 'form-control input-sm'}}) }}
</div>
<div class="form-group">
    {{ form_errors(form.address.street) }}
    {{ form_label(form.address.street, 'company.form.address.street.label'|trans({}, 'address')) }}
    {{ form_widget(form.address.street, {'attr': {'class': 'form-control input-sm'}}) }}
</div>
<div class="form-group">
    {{ form_errors(form.address.extraLine) }}
    {{ form_label(form.address.extraLine, 'company.form.address.extra_line.label'|trans({}, 'address')) }}
    {{ form_widget(form.address.extraLine, {'attr': {'class': 'form-control input-sm'}}) }}
</div>
You can’t perform that action at this time.