File size: 2,482 Bytes
d2897cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?php

declare(strict_types=1);

namespace Mautic\ConfigBundle\Form\DataTransformer;

use Mautic\ConfigBundle\Form\Type\EscapeTransformer;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Mautic\CoreBundle\Helper\Dsn\Dsn;
use Symfony\Component\Form\DataTransformerInterface;

/**
 * @implements DataTransformerInterface<string, array>
 */
class DsnTransformer implements DataTransformerInterface
{
    private const PASSWORD_MASK = '🔒';

    public function __construct(
        private CoreParametersHelper $coreParametersHelper,
        private EscapeTransformer $escapeTransformer,
        private string $configKey,
        private bool $allowEmpty
    ) {
    }

    /**
     * @return array<string, mixed>
     */
    public function transform($value): array
    {
        // unescape the DSN before the transformation to array
        $value = $this->escapeTransformer->transform((string) $value);

        try {
            $dsn = Dsn::fromString($value);
        } catch (\InvalidArgumentException) {
            return [];
        }

        return [
            'scheme'   => $dsn->getScheme(),
            'host'     => $dsn->getHost(),
            'user'     => $dsn->getUser(),
            'password' => $dsn->getPassword() ? self::PASSWORD_MASK : null,
            'port'     => $dsn->getPort(),
            'path'     => $dsn->getPath(),
            'options'  => $dsn->getOptions(),
        ];
    }

    /**
     * @param array<string, mixed> $value
     */
    public function reverseTransform($value): string
    {
        if ($this->allowEmpty && !array_filter($value)) {
            return '';
        }

        // unescape the values as they are escaped by the escape transformer applied to the child elements
        $value = $this->escapeTransformer->transform($value);

        $dsn = new Dsn(
            (string) $value['scheme'],
            (string) $value['host'],
            $value['user'],
            $value['password'],
            $value['port'] ? (int) $value['port'] : null,
            $value['path'],
            $value['options'],
        );

        if (self::PASSWORD_MASK === $dsn->getPassword()) {
            $previousDsn = Dsn::fromString($this->coreParametersHelper->get($this->configKey));
            $dsn         = $dsn->setPassword($previousDsn->getPassword());
        }

        // escape the DSN to prevent "missing parameter" errors
        return $this->escapeTransformer->reverseTransform((string) $dsn);
    }
}