<?php

namespace Velis\Dto\Traits;

use ReflectionAttribute;
use ReflectionException;
use ReflectionProperty;
use Velis\Dto\Casters\Castable;

/**
 * This trait is responsible for casting values using Casters assigned to the corresponding property.
 * @author Szymon Janaczek <szymon.janaczek@velistech.com>
 */
trait CastTrait
{
    /**
     * Casts a given value using Casters assigned to the corresponding property.
     * @throws ReflectionException
     */
    protected function cast(string $propertyName, mixed $value, $data = null)
    {
        // Get casters from property.
        $reflection = new ReflectionProperty($this, $propertyName);

        // Casters should implement Castable interface.
        $attributes = $reflection->getAttributes(Castable::class, ReflectionAttribute::IS_INSTANCEOF);

        // Iterate through casters and cast value using its logic.
        foreach ($attributes as $attribute) {
            $instance = $attribute->newInstance();
            $value = $instance->get($value, $data);
        }

        return $value;
    }
}
