LanguageFieldset   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 8

Importance

Changes 0
Metric Value
wmc 21
lcom 3
cbo 8
dl 0
loc 168
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A configureOptions() 0 19 1
A prepareAttributesCollection() 0 5 1
A setValue() 0 15 4
A getValue() 0 12 2
A getError() 0 14 4
A prepareLanguages() 0 9 2
A prepareLanguage() 0 12 1
A convertRepetitionsData() 0 11 3
A getChildValue() 0 11 2
1
<?php
2
/*
3
 * WellCommerce Open-Source E-Commerce Platform
4
 *
5
 * This file is part of the WellCommerce package.
6
 *
7
 * (c) Adam Piotrowski <[email protected]>
8
 *
9
 * For the full copyright and license information,
10
 * please view the LICENSE file that was distributed with this source code.
11
 */
12
13
namespace WellCommerce\Component\Form\Elements\Fieldset;
14
15
use Symfony\Component\OptionsResolver\OptionsResolver;
16
use Symfony\Component\PropertyAccess\PropertyPath;
17
use WellCommerce\Component\Form\DataTransformer\DataTransformerInterface;
18
use WellCommerce\Component\Form\Elements\Attribute;
19
use WellCommerce\Component\Form\Elements\AttributeCollection;
20
use WellCommerce\Component\Form\Elements\ElementInterface;
21
22
/**
23
 * Class LanguageFieldset
24
 *
25
 * @author Adam Piotrowski <[email protected]>
26
 */
27
class LanguageFieldset extends NestedFieldset implements FieldsetInterface
28
{
29
    protected $locales;
30
    
31
    public function __construct(array $locales)
32
    {
33
        parent::__construct();
34
        $this->locales = $locales;
35
    }
36
    
37
    /**
38
     * {@inheritdoc}
39
     */
40
    public function configureOptions(OptionsResolver $resolver)
41
    {
42
        parent::configureOptions($resolver);
43
        
44
        $resolver->setRequired([
45
            'languages',
46
        ]);
47
        
48
        $resolver->setDefaults([
49
            'languages' => $this->locales,
50
        ]);
51
        
52
        $resolver->setNormalizer('property_path', function ($options) {
53
            return new PropertyPath($options['name']);
54
        });
55
        
56
        $resolver->setAllowedTypes('languages', 'array');
57
        $resolver->setAllowedTypes('transformer', DataTransformerInterface::class);
58
    }
59
    
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function prepareAttributesCollection(AttributeCollection $collection)
64
    {
65
        parent::prepareAttributesCollection($collection);
66
        $collection->add(new Attribute('aoLanguages', $this->prepareLanguages(), Attribute::TYPE_ARRAY));
67
    }
68
    
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function setValue($data)
73
    {
74
        $accessor = $this->getPropertyAccessor();
75
        $data     = $this->convertRepetitionsData($data);
76
        
77
        $this->getChildren()->forAll(function (ElementInterface $child) use ($data, $accessor) {
78
            if (null !== $propertyPath = $child->getPropertyPath(true)) {
79
                $value = $accessor->getValue($data, $propertyPath);
80
                if (null === $value || '' === $value) {
81
                    $value = $child->getDefaultValue();
82
                }
83
                $child->setValue($value);
84
            }
85
        });
86
    }
87
    
88
    /**
89
     * Returns fieldset values
90
     *
91
     * @return array|mixed
92
     */
93
    public function getValue()
94
    {
95
        $values = [];
96
        
97
        $this->getChildren()->forAll(function (ElementInterface $child) use (&$values) {
98
            foreach ($this->locales as $locale) {
99
                $values[$locale['code']][$child->getName()] = $this->getChildValue($child, $locale['code']);
100
            }
101
        });
102
        
103
        return $values;
104
    }
105
    
106
    public function getError()
107
    {
108
        $errors = [];
109
        if (is_array($this->error)) {
110
            foreach ($this->error as $locale => $fields) {
111
                foreach ($fields as $field => $error) {
112
                    $errors[$locale][$field] = implode('.', $error);
113
                }
114
                
115
            }
116
        }
117
        
118
        return $errors;
0 ignored issues
show
Bug Best Practice introduced by Adam Piotrowski
The return type of return $errors; (array) is incompatible with the return type declared by the interface WellCommerce\Component\F...mentInterface::getError of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
119
    }
120
    
121
    /**
122
     * Prepares the languages
123
     *
124
     * @return array
125
     */
126
    protected function prepareLanguages()
127
    {
128
        $options = [];
129
        foreach ($this->options['languages'] as $language) {
130
            $options[] = $this->prepareLanguage($language);
131
        }
132
        
133
        return $options;
134
    }
135
    
136
    /**
137
     * Prepares language to use it as element attribute
138
     *
139
     * @param $language
140
     *
141
     * @return array
142
     */
143
    protected function prepareLanguage($language)
144
    {
145
        $value = addslashes($language['code']);
146
        $label = addslashes($language['code']);
147
        $flag  = addslashes(sprintf('%s.png', substr($label, 0, 2)));
148
        
149
        return [
150
            'sValue' => $value,
151
            'sLabel' => $label,
152
            'sFlag'  => $flag,
153
        ];
154
    }
155
    
156
    /**
157
     * Flips language repetitions
158
     *
159
     * @param array $data
160
     *
161
     * @return array
162
     */
163
    protected function convertRepetitionsData($data)
164
    {
165
        $values = [];
166
        foreach ($data as $locale => $translation) {
167
            foreach ($translation as $fieldName => $fieldValue) {
168
                $values[$fieldName][$locale] = $fieldValue;
169
            }
170
        }
171
        
172
        return $values;
173
    }
174
    
175
    /**
176
     * Returns child values
177
     *
178
     * @param ElementInterface $child
179
     * @param string           $locale
180
     *
181
     * @return mixed|null
182
     */
183
    protected function getChildValue(ElementInterface $child, $locale)
184
    {
185
        $accessor = $this->getPropertyAccessor();
186
        $value    = $child->getValue();
187
        
188
        if (is_array($value)) {
189
            return $accessor->getValue($value, "[{$locale}]");
190
        }
191
        
192
        return null;
193
    }
194
}
195