CallbackTransformer.php$0 ➔ __construct()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
dl 0
loc 5
ccs 0
cts 0
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Bdf\Form\Attribute\Element;
4
5
use Attribute;
6
use Bdf\Form\Attribute\AttributeForm;
7
use Bdf\Form\Attribute\Child\CallbackModelTransformer;
8
use Bdf\Form\Attribute\ChildBuilderAttributeInterface;
9
use Bdf\Form\Attribute\Processor\CodeGenerator\AttributesProcessorGenerator;
10
use Bdf\Form\Attribute\Processor\CodeGenerator\ClassGenerator;
11
use Bdf\Form\Attribute\Processor\CodeGenerator\TransformerClassGenerator;
12
use Bdf\Form\Attribute\Processor\GenerateConfiguratorStrategy;
13
use Bdf\Form\Child\ChildBuilderInterface;
14
use Bdf\Form\ElementBuilderInterface;
15
use Bdf\Form\ElementInterface;
16
use Bdf\Form\Transformer\TransformerInterface;
17
use Nette\PhpGenerator\ClassType;
18
use Nette\PhpGenerator\Factory;
19
use Nette\PhpGenerator\Literal;
20
use Nette\PhpGenerator\Method;
21
use Nette\PhpGenerator\PsrPrinter;
22
23
/**
24
 * Add a HTTP transformer on the child element, by using method
25
 *
26
 * Transformation to entity and to input can be separated in two different method.
27
 * Those methods take the value and the input element as parameters, and should return the transformed value
28
 * If dedicated methods are not used, but the unified one, the third parameter is provided :
29
 * - on true the transformation is to the entity
30
 * - on false the transformation is to the input
31
 *
32
 * This attribute is equivalent to call :
33
 * <code>
34
 * // For unified callback
35
 * $builder->string('foo')->transformer([$this, 'myTransformer']);
36
 *
37
 * // When using two methods (toHttp: 'transformFooToHttp', fromHttp: 'transformFooFromHttp')
38
 * $builder->string('foo')->transformer(function ($value, ElementInterface $input, bool $toPhp) {
39
 *     return $toPhp ? $this->transformFooFromHttp($value, $input) : $this->transformFooToHttp($value, $input);
40
 * });
41
 * </code>
42
 *
43
 * Usage:
44
 * <code>
45
 * class MyForm extends AttributeForm
46
 * {
47
 *     #[CallbackTransformer(fromHttp: 'fooFromHttp', toHttp: 'fooToHttp')]
48
 *     private IntegerElement $foo;
49
 *
50
 *     // With unified transformer (same as above)
51
 *     #[CallbackTransformer('barTransformer')]
52
 *     private IntegerElement $bar;
53
 *
54
 *     public function fooFromHttp(string $value, IntegerElement $input): int
55
 *     {
56
 *         return hexdec($value);
57
 *     }
58
 *
59
 *     public function fooToHttp(int $value, IntegerElement $input): string
60
 *     {
61
 *         return dechex($value);
62
 *     }
63
 *
64
 *     public function barTransformer($value, IntegerElement $input, bool $toPhp)
65
 *     {
66
 *         return $toPhp ? hexdec($value) : dechex($value);
67
 *     }
68
 * }
69
 * </code>
70
 *
71
 * @implements ChildBuilderAttributeInterface<\Bdf\Form\ElementBuilderInterface>
72
 *
73
 * @see ElementBuilderInterface::transformer() The called method
74
 * @see Transformer For use a transformer class as transformer
75
 * @see CallbackModelTransformer For use transformer in same way, but for model transformer intead of http one
76
 */
77
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
78
final class CallbackTransformer implements ChildBuilderAttributeInterface
79
{
80 15
    public function __construct(
81
        /**
82
         * Method name use to define the unified transformer method
83
         * If defined, the other parameters will be ignored
84
         *
85
         * @var literal-string|null
86
         * @readonly
87
         */
88
        private ?string $callback = null,
89
        /**
90
         * Method name use to define the transformation process from http value to the input
91
         *
92
         * @var literal-string|null
93
         * @readonly
94
         */
95
        private ?string $fromHttp = null,
96
        /**
97
         * Method name use to define the transformation process from input value to http format
98
         *
99
         * @var literal-string|null
100
         * @readonly
101
         */
102
        private ?string $toHttp = null,
103
    ) {
104 15
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109 6
    public function applyOnChildBuilder(AttributeForm $form, ChildBuilderInterface $builder): void
110
    {
111 6
        if ($this->callback) {
112 4
            $builder->transformer([$form, $this->callback]);
113 4
            return;
114
        }
115
116 3
        $builder->transformer(new class ($form, $this->fromHttp, $this->toHttp) implements TransformerInterface {
117
            public function __construct(
118
                private AttributeForm $form,
119
                private ?string $fromHttp,
120
                private ?string $toHttp,
121
            ) {
122 3
            }
123
124
            /**
125
             * {@inheritdoc}
126
             */
127
            public function transformToHttp($value, ElementInterface $input)
128
            {
129 2
                if (!$this->toHttp) {
130 1
                    return $value;
131
                }
132
133 2
                return $this->form->{$this->toHttp}($value, $input);
134
            }
135
136
            /**
137
             * {@inheritdoc}
138
             */
139
            public function transformFromHttp($value, ElementInterface $input)
140
            {
141 3
                if (!$this->fromHttp) {
142 1
                    return $value;
143
                }
144
145 3
                return $this->form->{$this->fromHttp}($value, $input);
146
            }
147 3
        });
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 9
    public function generateCodeForChildBuilder(string $name, AttributesProcessorGenerator $generator, AttributeForm $form): void
154
    {
155 9
        if ($this->callback) {
156 7
            $generator->line('$?->transformer([$form, ?]);', [$name, $this->callback]);
157 7
            return;
158
        }
159
160 4
        $transformer = new TransformerClassGenerator($generator->namespace(), $generator->printer());
161
162 4
        $transformer->withPromotedProperty('form')->setPrivate();
163
164 4
        if ($this->toHttp) {
165 3
            $transformer->toHttp()->setBody('return $this->form->?($value, $input);', [$this->toHttp]);
166
        } else {
167 2
            $transformer->toHttp()->setBody('return $value;');
168
        }
169
170 4
        if ($this->fromHttp) {
171 4
            $transformer->fromHttp()->setBody('return $this->form->?($value, $input);', [$this->fromHttp]);
172
        } else {
173 1
            $transformer->fromHttp()->setBody('return $value;');
174
        }
175
176 4
        $generator->line(
177 4
            '$?->transformer(new class ($form) ?);',
178 4
            [$name, new Literal($transformer->generateClass())]
179 4
        );
180
    }
181
}
182