The CSCFA csr Division PHP implementation

1.0.0 2017-03-19 16:41 UTC

This package is not auto-updated.

Last update: 2024-05-01 18:07:08 UTC


README

This project is the PHP implementation of the csr3 specification.

The data transfer objects are elements used to encapsulate the data when they must go through multiple elements of an application. The DTO acts as a container.

SensioLabsInsight

Basic usage

The CSR3 project define a generic DTO object :

use CSDT\CSR3\CSR3GenericDTO;

$dto = new CSR3GenericDTO();

The CSR3GenericDTO is an instance that implement CSR3DTOInterface. This interface extend ArrayAccess and Iterator interfaces.

The ArrayAccess iplementation

By using the ArrayAccess interface, the CSR3GenericDTO allow to be used as an array.

// ...

if (isset($user) && !empty($user)) {
    $dto['user_instance'] = $user;
}

// ...

if (isset($dto['user_instance']) {
    $user = $dto['user_instance'];
    
    if ($user->isLocked()) {
        unset($dto['user_instance']);
    }
}
The Iterator iplementation

By using the Iterator interface, the CSR3GenericDTO allow to be used as an iterator.

$dto['hell'] = 'o w';
$dto['or'] = 'ld';

foreach ($dto as $key => $value) {
    echo $key . $value;
}

// Output : "hello world"
The CSR3DTOInterface iplementation

The CSR3DTOInterface is the default access feature of the CSR3 DTOs. It allow to set and get attributes.

$dto->setAttributes(['a' => 1, 'b' => 2]);

var_dump($dto->getAttributes());
/* array(2) {
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
} */


$dto->setAttribute('a', 3);

var_dump($dto->getAttribute('b')); // int(2)
var_dump($dto->getAttributes());
/* array(2) {
  ["a"]=>
  int(3)
  ["b"]=>
  int(2)
} */

Adding custom methods

The CSR3GenericDTO is a final class and cannot be extended as it. But it extend an abstract class : the AbstractCSR3DTO that define all the logic needed to implement the CSR3DTOInterface.

Imagine you want to create a DTO that store a specific context and you want to be able to retreive this by a method call. You can create a DTO class as the following :

use CSDT\CSR3\Abstracts\AbstractCSR3DTO;

class ContextDTO extends AbstractCSR3DTO
{
    public function setContext($context)
    {
        $this['context'] = $context;
    }
    
    public function getContext($context)
    {
        return $this['context'] ?? [];
    }
}

Using custom class properties

As seen in the custom method addition, you'll must create your own class :

use CSDT\CSR3\Abstracts\AbstractCSR3DTO;

class ContextDTO extends AbstractCSR3DTO
{
    protected $context = [];

    public function setContext($context)
    {
        $this->context = $context;
    }
    
    public function getContext($context)
    {
        return $this->context;
    }
}

The problem yu will discover by using this custom class is that the ArrayAccess and iterator property are not able to handle the $context property. To avoid this issue, you'll need to extend the AbstractCSR3PropertyDTO instead of the AbstractCSR3DTO.

use CSDT\CSR3\Abstracts\AbstractCSR3DTO;

class ContextDTO extends AbstractCSR3PropertyDTO
{
    protected $context = [];

    public function setContext($context)
    {
        $this->['context'] = $context;
    }
    
    public function getContext($context)
    {
        return $this['context'];
    }
}

💢 Note the AbstractCSR3PropertyDTO is not able to process private properties as it. This is in fact the POO structure of the PHP.

Using private properties

To be able to manage the private properties of your DTO's, you'll must override three methods of the AbstractCSR3PropertyDTO :

use CSDT\CSR3\Abstracts\AbstractCSR3DTO;

class ContextDTO extends AbstractCSR3PropertyDTO
{
    private $context = [];
    
    protected function getProperties() : array
    {
        return array_merge(
            parent::getProperties(),
            ['context']
        );
    }
    
    protected function setProperty(string $propertyName, $propertyValue)
    {
        if ($propertyName == 'context') {
            $this->setContext($propertyValue);
            return $this;
        }

        return parent::setProperty($propertyName, $propertyValue);
    }

    protected function getProperty(string $propertyName)
    {
        if (propertyName == 'context') {
            return $this->getContext();
        }

        return parent::getProperty($propertyName);
    }

    public function setContext($context)
    {
        $this->context = $context;
    }
    
    public function getContext($context)
    {
        return $this->context;
    }
}

❕ These three methods work in cooperation and cannot be override without the other to enable the fully private property support.

Internal key-words and how to override them

The AbstractCSR3DTO and AbstractCSR3PropertyDTO defines an attributes and traversingPosition properties. The first one store the attributes of the DTO, the second store the internal iteration pointer. It is possible to override them by setting a attributeContainer and a positionContainer properties that store the attributes names to use instead of the two initial properties.

💢 The attributeContainer and positionContainer properties are key-words and cannot be overrides.

Using logic without CSR3 interfaces

The complete logic of this implementation is encapsulated inside a CSR3DTOTrait and a CSR3PropertyDTOTrait.

use CSDT\CSR3\Traits\CSR3DTOTrait;

class AttributeDTO
{
    use CSR3DTOTrait;

    private $attributes = [];
    
    private $traversingPosition = 0;
}
use CSDT\CSR3\Traits\CSR3DTOPropertyTrait;

class ContextDTO
{
    use CSR3DTOPropertyTrait;

    private $attributes = [];
    
    private $traversingPosition = 0;
    
    private $context = [];
    
    protected function getProperties() : array
    {
        return array_merge(
            parent::getProperties(),
            ['context']
        );
    }
    
    protected function setProperty(string $propertyName, $propertyValue)
    {
        if ($propertyName == 'context') {
            $this->setContext($propertyValue);
            return $this;
        }

        return parent::setProperty($propertyName, $propertyValue);
    }

    protected function getProperty(string $propertyName)
    {
        if (propertyName == 'context') {
            return $this->getContext();
        }

        return parent::getProperty($propertyName);
    }

    public function setContext($context)
    {
        $this->context = $context;
    }
    
    public function getContext($context)
    {
        return $this->context;
    }
}