Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about modifying values of a source #111

Open
aiglesiasn opened this issue Apr 13, 2022 · 2 comments
Open

Question about modifying values of a source #111

aiglesiasn opened this issue Apr 13, 2022 · 2 comments

Comments

@aiglesiasn
Copy link

Hi Romain!
Thank you for your great work!

I have a question about what approach should I take.

We were using version 0.3.0 of Valinor until now, and we created our custom sources for different classes, but as we are migration to 0.7.0 I found the Mapper/Source classes very useful but I want to ask you if there's anyway I can modify a value of a multidimensional array key to a (array) json_decode($value)

CONTEXT

ClientTimeline Class constructor:

/**
     * @param string $identifier
     * @param string $type
     * @param string|null $content
     * @param ClientTimelineMetadata|null $metadata
     * @param \DateTimeInterface $createdAt
     * @param \DateTimeInterface|null $updatedAt
     */
    public function __construct(
        private string $identifier,
        private string $type,
        private ?string $content,
        private ?ClientTimelineMetadata $metadata,
        private \DateTimeInterface $createdAt,
        private ?\DateTimeInterface $updatedAt,
    ) {
    }

$metadata, ClientTimelineMetadata Class constructor:

/**
     * @param bool|null $complete
     * @param DateTimeInterface $date
     */
    public function __construct(
        private ?bool $complete,
        private DateTimeInterface $date,
    ) {
    }

In Valinor 0.3.0 I used this Source:

class ClientTimelineTransformationSource implements \IteratorAggregate
{
    private array $source = [];

    public function __construct(iterable $source)
    {
        $this->source = $this->transform($source);
    }

    public array $keyMap = [
        'timeline_type'  => 'type',
        'created_at' => 'createdAt',
        'updated_at' => 'updatedAt',
    ];

    private function transform(iterable $source): array
    {
        $array = [];

        foreach ($source as $key => $value) {
            if (is_iterable($value)) {
                return $this->transform($value);
            }

            if ($key === 'metadata') {
                $array[$key] = json_decode($value, true);
            } else {
                $array[$this->keyMap[$key] ?? $key] = $value;
            }
        }

        return $array;
    }

    public function getIterator()
    {
        yield from $this->source;
    }

    /**
     * @return array
     */
    public function getSource(): array
    {
        return $this->source;
    }
}

With this source, I mapped a key to another and CamelCase the other keys, but also, for key metadata I use json_decode to decode a json string, so Valinor can Map metadata into the ClientTimeline.

For Valinor 0.7.0 I'm using this:

$returnArray = [];
                foreach ($clientTimelines as $clientTimeline) {
                    // Modify metadata json string to array
                    if (is_string($clientTimeline['metadata'])) {
                        $clientTimeline['metadata'] =  (array) json_decode($clientTimeline['metadata']);
                    }

                    $returnArray[] = (new MapperBuilder())
                        ->mapper()->map(
                            ClientTimeline::class,
                            Source::array($clientTimeline)
                                ->map(
                                    [
                                        'timeline_type' => 'type',
                                    ]
                                )
                                ->camelCaseKeys()
                        );
                }
                return $returnArray;

I was wondering is there any way I can modify the value of the metadata key into (array) json_decode($metadata) with a value modifier or something like it.

Hope this made sense.

Thank you for all your work and for your time.

All the best!

Andrés

@romm
Copy link
Member

romm commented May 2, 2022

Hi @aiglesiasn, your approach seems to be valid for this usecase, although it makes me think we should probably ship a source modifier that could handle "automatic" json decoding among the input.

I'll keep you updated here. 🙂

@aiglesiasn
Copy link
Author

Thank you @romm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants