Skip to content

Policies

ScorpioT1000 edited this page Jun 15, 2017 · 23 revisions

Policies allow you to create sets of rules how to transform your data to and from Entity and sub-Entities. There are three types of policies: Global, Local and inherited from parent. You can define them depending on the type. Note: all the examples use relative namespaces.

Global Policies

Global policies are defined in php documentation comments:

/** @Policy\To\Auto
  * @Policy\From\Skip */
protected $propertyName;

Global policies have lower priority level than local and same level as inherited from parent.

Local Policies

Local policies are defined inside Policy class:

$policy = (new Policy\Auto)->inside([
    'propertyName' => new Policy\To\Skip
])

Local policies always override global and inherited from parent if specified.

Inheritance from parent

If you specify a policy for entity and it has 'propagating' option set to true, it is passed to sub-entities with lower priority:

/** @ORM\Entity */
class A implements ITransformable {
    use Transformable;

    /** @ORM\Column(type="datetime") */
    protected $dt;

    // ...
}

/** @ORM\Entity */
class B implements ITransformable {
    use Transformable;

    /** @ORM\OneToOne(targetEntity="A") */
    protected $a;

    /** @ORM\Column(type="datetime") */
    protected $dt;

    // ...
}

$e = (new B())->setA(new A());

$result = $e->toArray(
    (new Policy\To\FormatDateTime())->format('Y-m')
)

Here Policy\To\FormatDateTime will be used for B::dt, passed to A with lower priority and will be used for A::dt.

But if Policy's 'propagating' option is set to false, a new Auto policy with lower priority will be passed.

General

Policy\Auto

Combines Policy\To\Auto and Policy\From\Auto together. Automatically decides what to store, it typically uses getter/setter of the field.

Global policy: the same behaviour when field isn't specified.

Local policy: overrides and ignores all the global policy parameters.

Policy\Skip

Combines Policy\To\Skip and Policy\From\Skip together.

Skips the field in both ITransformabe::fromArray and ITransformabe::toArray.

To

These policies are used in ITransformabe::toArray and ignored in ITransformabe::fromArray.

Policy\To\Auto

Automatically decides what to store, it typically uses getter/setter

Global policy: the same behaviour when field isn't specified.

Local policy: overrides and ignores all the global policy parameters.

Policy\To\Custom

Uses closure to override the default formatting behaviour.

Methods

    /** Sets closure to format the SCALAR field.
     * @param \Closure $handler function($value, $columnType)
     *      The $value is passed to closure BEFORE any transformation.
     *      $columnType can be one of Doctrine DBAL types or null for non-doctrine type.
     *      @see http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html#mapping-matrix
     *      The closure function MUST return a new value that will be placed at the result array.
     * 
     * @return Custom */
    public function format(\Closure $handler)
    
    /** Sets closure to transform the RELATION (Entity or Collection) field into array.
     * @param \Closure $handler function($original, $transformed)
     *      $original can be an Entity, Collection or null
     *      $transformed is a transformation result, it can be changed and returned.
     *      The closure function MUST return a new value that will be placed at the result array.
     * 
     * @return Custom */
    public function transform(\Closure $handler)

Usage

Local (only):

$formatted = (new Policy\To\Custom())->format(function($value, $columnType) {
    return $value * 1000;
});

$transformed = (new Policy\To\Custom())->transform(function($original, $transformed) {
    $transformed['value'] = $original->getValue() * 1000;
    return $transformed;
});

$nulled = (new Policy\To\Custom())->transform(function($original, $transformed) {
    return null;
});

Policy\To\FetchPaginate

Sets the fetch offset and limit for the result collection.

It works with OneToMany and ManyToMany associations ONLY!

It works effectively when "fetch" option is set to "EXTRA_LAZY" - sends offset and limit instruction directly to the database.

@see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html

It's not inherited from parent's global policy.

It's not inherited from parent's policy (!). Specify inside() to change behaviour.

Policy\To\FormatDateTime

Formats datetime according to \DateTime::format schema

@see http://php.net/manual/en/function.date.php#refsect1-function.date-parameters

Note: ITransformable always works in UTC timezone.

Methods

/** @return FormatDateTime */
public function format($f)

Usage

Global:

    /** @Policy\To\FormatDateTime
     * @ORM\Column(type="datetime") */
    protected $dt1;
    
    /** @Policy\To\FormatDateTime(format="Y_m_d_H_i_s")
     * @ORM\Column(type="datetime") */
    protected $dt2;

Local:

        $policy = (new Policy\To\Auto)->inside([
            'dt1' => new Policy\To\FormatDateTime,
            'dt2' => new Policy\To\FormatDateTime(['format' => "Y_m_d_H_i_s"])
        ]);

Policy\To\KeepDateTime

Don't convert \DateTime to ISO8601 string in ITransformabe::toArray

@see http://www.iso.org/iso/catalogue_detail?csnumber=40874

Note: ITransformable always works in UTC timezone.

Policy\To\Skip

Excludes the field from result.

From

These policies are used in ITransformabe::fromArray and ignored in ITransformabe::toArray.

Policy\From\Auto

Automatically decides what to store, it typically uses getter/setter of the field.

Global policy: the same behaviour when field isn't specified.

Local policy: overrides and ignores all the global policy parameters.

Policy\From\Custom

Uses closure to manually parse the field into Entity.

Methods

    /** Sets closure to prove if the field should be changed or skipped.
     * @param \Closure $c function($value,
     *                             $propertyName,
     *                             \Indaxia\OTR\ITransformable $entity,
     *                             \Doctrine\ORM\EntityManagerInterface $em)
     *      The closure function MUST return TRUE if the field has been processed
     *      or FALSE to let OTR process it using Auto policy.
     *      
     * @return Custom */
    public function parse(\Closure $c)

Usage

Local (only):

(new Policy\From\Custom())->parse(function($value, $propertyName, $e, $em) {
    return (!$e->isAdmin() || $e->isBlocked()); // false = process automaticaly
});

Policy\From\DenyNew

Don't create a new sub-Entity or scalar when it needed, skip instead in ITransformabe::fromArray.

It's applicable to Collection too.

It's applicable to scalar fields: it denies to set the new value if the value is empty.

Note: it won't work with non-nullable numbers. Numbers cannot be "empty". @see DenyUpdate

It's not inherited from parent's policy (!). Specify inside() to change behaviour.

Policy\From\DenyUnset

Don't null the existent sub-Entity or scalars when it needed, skip instead in ITransformabe::fromArray.

It's applicable to Collection too, but it works really slow when "fetch" option is set to "LAZY". Use fetch options "EAGER" or "EXTRA_LAZY" instead.

It's applicable to scalar fields: it denies to clear the value if it is set.

Note: it won't work with non-nullable numbers. Numbers cannot be "empty".

It's not inherited from parent's policy (!). Specify inside() to change behaviour.

Warning: it allows to assign new entities instead of existent. Use Skip to deny any changes.

Policy\From\DenyUpdate

Don't update the existent scalar or sub-Entity when it needed in ITransformabe::fromArray.

It's applicable to scalar fields: it denies to change new value if the value is already set.

It's applicable to numbers even when numbers are 0, 0.0, "0.0" etc.

It's applicable to Collection and Entity relations.

It's not inherited from parent's policy (!). Specify inside() to change behaviour.

Set $allowExternal to true to allow RETRIEVING of external entities from the database.

Set $allowExistent to true to allow UPDATING of external or existent entity.

Properties

    /** Allows updating of any entity from the given source array, regardless of where it retrieved from. */
    public $allowExistent = false;
    
    /** If a new id is specified, it calls $entityManager->getReference()
      * to retrieve the required entity from the database. */
    public $allowExternal = false;

Policy\From\DenyNewUnset

Use it to combine DenyNew and DenyUnset.

Keep in mind that DenyFrom policies are not merged automatically.

Policy\From\DenyNewUpdate

Use it to combine DenyNew and DenyUpdate.

Keep in mind that DenyFrom policies are not merged automatically.

Policy\From\DenyUnsetUpdate

Use it to combine DenyUnset and DenyUpdate.

Keep in mind that DenyFrom policies are not merged automatically.

Policy\From\Skip

Skips the field from parsing.