Completed
Pull Request — master (#90)
by Arnaud
07:39 queued 05:31
created

FieldFactory::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 6
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 3
crap 2
1
<?php
2
3
namespace LAG\AdminBundle\Field\Factory;
4
5
use Exception;
6
use LAG\AdminBundle\Action\Configuration\ActionConfiguration;
7
use LAG\AdminBundle\Application\Configuration\ApplicationConfiguration;
8
use LAG\AdminBundle\Application\Configuration\ApplicationConfigurationStorage;
9
use LAG\AdminBundle\Field\FieldInterface;
10
use LAG\AdminBundle\Field\TwigAwareInterface;
11
use LAG\AdminBundle\Field\TranslatorAwareInterface;
12
use Symfony\Component\OptionsResolver\OptionsResolver;
13
use Symfony\Component\Translation\TranslatorInterface;
14
use Twig_Environment;
15
16
/**
17
 * Field factory. Instances fields with its renderer.
18
 */
19
class FieldFactory
20
{
21
    /**
22
     * Application configuration
23
     *
24
     * @var ApplicationConfiguration
25
     */
26
    protected $configuration;
27
28
    /**
29
     * Field class mapping array, indexed by field type.
30
     *
31
     * @var array
32
     */
33
    protected $fieldsMapping = [];
34
35
    /**
36
     * Translator for field values.
37
     *
38
     * @var TranslatorInterface
39
     */
40
    protected $translator;
41
42
    /**
43
     * Twig engine.
44
     *
45
     * @var Twig_Environment
46
     */
47
    protected $twig;
48
    
49
    /**
50
     * @var ConfigurationFactory
51
     */
52
    protected $configurationFactory;
53
    
54
    /**
55 1
     * FieldFactory constructor.
56
     *
57
     * @param ApplicationConfigurationStorage                     $applicationConfigurationStorage
58
     * @param ConfigurationFactory $configurationFactory
59
     * @param TranslatorInterface                                 $translator
60 1
     * @param Twig_Environment                                    $twig
61 1
     */
62 1
    public function __construct(
63 1
        ApplicationConfigurationStorage $applicationConfigurationStorage,
64 1
        ConfigurationFactory $configurationFactory,
65 1
        TranslatorInterface $translator,
66 1
        Twig_Environment $twig
67
    ) {
68
        $this->configuration = $applicationConfigurationStorage->getApplicationConfiguration();
69
        $this->fieldsMapping = $this
70
            ->configuration
71
            ->getParameter('fields_mapping'); // shortcut to field mapping array
72
        $this->translator = $translator;
73
        $this->twig = $twig;
74
        $this->configurationFactory = $configurationFactory;
75
    }
76
    
77
    public function getFields(ActionConfiguration $configuration)
78
    {
79
        $fields = [];
80
    
81
        foreach ($configuration->getParameter('fields') as $field => $fieldConfiguration) {
82
            $fields[] = $this->create($field, $fieldConfiguration, $configuration);
83
        }
84
    
85
        return $fields;
86
    }
87
    
88
    
89
    /**
90
     * Create a new field with its renderer.
91
     *
92
     * @param                     $fieldName
93
     * @param array               $configuration
94
     * @param ActionConfiguration $actionConfiguration
95
     *
96
     * @return FieldInterface
97
     * @throws Exception
98
     */
99
    public function create($fieldName, array $configuration = [], ActionConfiguration $actionConfiguration)
100
    {
101
        $configuration = $this->resolveTopLevelConfiguration($configuration, $actionConfiguration);
102
        $field = $this->instanciateField($fieldName, $configuration['type']);
103
        
104
        $fieldConfiguration = $this
105
            ->configurationFactory
106
            ->create($field, $configuration)
107
        ;
108
        $field->setConfiguration($fieldConfiguration);
109
        
110
        return $field;
111
    }
112
113
    /**
114
     * Return field class according to the field type. If the type is not present in the field mapping array, an
115
     * exception will be thrown.
116
     *
117
     * @param $type
118
     * @return string
119
     * @throws Exception
120
     */
121
    private function getFieldMapping($type)
122
    {
123
        if (!array_key_exists($type, $this->fieldsMapping)) {
124
            throw new Exception("Field type {$type} not found in field mapping. Check your configuration");
125
        }
126
127
        return $this->fieldsMapping[$type];
128
    }
129
    
130
    /**
131
     * @param $name
132
     * @param $type
133
     *
134
     * @return FieldInterface
135
     *
136
     * @throws Exception
137
     */
138
    private function instanciateField($name, $type)
139
    {
140
        $fieldClass = $this->getFieldMapping($type);
141
        $field = new $fieldClass($name);
142
    
143
        if (!$field instanceof FieldInterface) {
144
            throw new Exception("Field class {$fieldClass} must implements ".FieldInterface::class);
145
        }
146
    
147
        if ($field instanceof TranslatorAwareInterface) {
148
            $field->setTranslator($this->translator);
149
        }
150
        if ($field instanceof TwigAwareInterface) {
151
            $field->setTwig($this->twig);
152
        }
153
    
154
        return $field;
155
    }
156
    
157
    private function resolveTopLevelConfiguration(array $configuration, ActionConfiguration $actionConfiguration)
158
    {
159
        $resolver = new OptionsResolver();
160
        $resolver
161
            ->setDefaults([
162
                'type' => 'string',
163
                'options' => [],
164
            ])
165
            // Set allowed fields type from tagged services
166
            ->setAllowedValues('type', array_keys($this->fieldsMapping))
167
            ->setAllowedTypes('type', 'string')
168
            ->setAllowedTypes('options', 'array')
169
        ;
170
        $configuration = $resolver->resolve($configuration);
171
    
172
        // for collection of fields, we resolve the configuration of each item
173
        if ($configuration['type'] == 'collection') {
174
            $items = [];
175
        
176
            foreach ($configuration['options'] as $itemFieldName => $itemFieldConfiguration) {
177
                // configuration should be an array
178
                if (!$itemFieldConfiguration) {
179
                    $itemFieldConfiguration = [];
180
                }
181
                // type should exists
182
                if (!array_key_exists('type', $configuration)) {
183
                    throw new Exception("Missing type configuration for field {$itemFieldName}");
184
                }
185
                // create collection item
186
                $items[] = $this->create($itemFieldName, $itemFieldConfiguration, $actionConfiguration);
187
            }
188
            // add created item to the field options
189
            $configuration['options'] = [
190
                'fields' => $items,
191
            ];
192
        }
193
    
194
        return $configuration;
195
    }
196
}
197