TranslationAdminListConfigurator   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 291
Duplicated Lines 6.87 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 42
lcom 1
cbo 10
dl 20
loc 291
ccs 0
cts 184
cp 0
rs 9.0399
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A canAdd() 0 4 1
A getBundleName() 0 4 1
A getEntityName() 0 4 1
A getControllerPath() 0 4 1
A __construct() 0 6 1
A buildFilters() 0 11 1
A buildFields() 0 6 1
A getExportFields() 0 17 3
A addExportField() 0 6 1
A canEdit() 0 4 1
A canEditInline() 0 4 1
A canExport() 0 4 1
A getPathByConvention() 8 8 2
A getAdminType() 0 4 1
F getQueryBuilder() 12 132 25

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like TranslationAdminListConfigurator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TranslationAdminListConfigurator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Kunstmaan\TranslatorBundle\AdminList;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Query\QueryBuilder;
7
use Kunstmaan\AdminListBundle\AdminList\Configurator\AbstractDoctrineDBALAdminListConfigurator;
8
use Kunstmaan\AdminListBundle\AdminList\Configurator\ChangeableLimitInterface;
9
use Kunstmaan\AdminListBundle\AdminList\Field;
10
use Kunstmaan\AdminListBundle\AdminList\FieldAlias;
11
use Kunstmaan\AdminListBundle\AdminList\FilterType\DBAL\EnumerationFilterType;
12
use Kunstmaan\AdminListBundle\AdminList\FilterType\DBAL\StringFilterType;
13
use Kunstmaan\AdminListBundle\Traits\ChangeableLimitTrait;
14
use Kunstmaan\TranslatorBundle\Entity\Translation;
15
16
/**
17
 * TranslationAdminListConfigurator
18
 */
19
class TranslationAdminListConfigurator extends AbstractDoctrineDBALAdminListConfigurator implements ChangeableLimitInterface
20
{
21
    use ChangeableLimitTrait;
22
23
    /**
24
     * @var array
25
     */
26
    protected $locales;
27
28
    /**
29
     * @var string
30
     */
31
    protected $locale;
32
33
    /**
34
     * @var Field[]
35
     */
36
    private $exportFields = [];
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
37
38
    /**
39
     * @param Connection $connection
40
     * @param array      $locales
41
     */
42
    public function __construct(Connection $connection, array $locales)
43
    {
44
        parent::__construct($connection);
45
        $this->locales = $locales;
46
        $this->setCountField('CONCAT(b.translation_id)');
47
    }
48
49
    /**
50
     * Configure filters
51
     */
52
    public function buildFilters()
53
    {
54
        $this->addFilter('status', new StringFilterType('status'), 'kuma_translator.adminlist.filter.status');
55
        $this->addFilter('domain', new StringFilterType('domain'), 'kuma_translator.adminlist.filter.domain');
56
        $this->addFilter('keyword', new StringFilterType('keyword'), 'kuma_translator.adminlist.filter.keyword');
57
        $this->addFilter('text', new StringFilterType('text'), 'kuma_translator.adminlist.filter.text');
58
        $this->addFilter('locale', new EnumerationFilterType('locale'), 'kuma_translator.adminlist.filter.locale', array_combine(
59
            $this->locales,
60
            $this->locales
61
        ));
62
    }
63
64
    /**
65
     * Configure the visible columns
66
     */
67
    public function buildFields()
68
    {
69
        $this->addField('domain', 'kuma_translator.adminlist.header.domain', true);
70
        $this->addField('keyword', 'kuma_translator.adminlist.header.keyword', true);
71
        $this->addField('status', 'kuma_translator.adminlist.header.status', true);
72
    }
73
74
    public function getExportFields()
75
    {
76
        if (empty($this->exportFields)) {
77
            $this->addExportField('domain', 'kuma_translator.adminlist.header.domain');
78
            $this->addExportField('keyword', 'kuma_translator.adminlist.header.keyword');
79
80
            $this->locales = array_unique($this->locales);
81
            // Field building hack...
82
            foreach ($this->locales as $locale) {
83
                $this->addExportField($locale, strtoupper($locale));
84
            }
85
86
            $this->addExportField('status', 'kuma_translator.adminlist.header.status');
87
        }
88
89
        return $this->exportFields;
90
    }
91
92
    public function addExportField($name, $header, $template = null, FieldAlias $alias = null)
93
    {
94
        $this->exportFields[] = new Field($name, $header);
95
96
        return $this;
97
    }
98
99
    /**
100
     * @return bool
101
     */
102
    public function canAdd()
103
    {
104
        return true;
105
    }
106
107
    /**
108
     * @param object|array $item
109
     *
110
     * @return bool
111
     */
112
    public function canEdit($item)
113
    {
114
        return false;
115
    }
116
117
    /**
118
     * @param object|array $item
119
     *
120
     * @return bool
121
     */
122
    public function canEditInline($item)
123
    {
124
        return true;
125
    }
126
127
    /**
128
     * @return bool
129
     */
130
    public function canExport()
131
    {
132
        return true;
133
    }
134
135
    /**
136
     * Override path convention (because settings is a virtual admin subtree)
137
     *
138
     * @param string $suffix
0 ignored issues
show
Documentation introduced by
Should the type for parameter $suffix not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
139
     *
140
     * @return string
141
     */
142 View Code Duplication
    public function getPathByConvention($suffix = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
    {
144
        if (empty($suffix)) {
145
            return sprintf('%s_settings_%ss', $this->getBundleName(), strtolower($this->getEntityName()));
146
        }
147
148
        return sprintf('%s_settings_%ss_%s', $this->getBundleName(), strtolower($this->getEntityName()), $suffix);
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    public function getAdminType($item)
155
    {
156
        return null;
157
    }
158
159
    public function getBundleName()
160
    {
161
        return 'KunstmaanTranslatorBundle';
162
    }
163
164
    public function getEntityName()
165
    {
166
        return 'Translation';
167
    }
168
169
    public function getControllerPath()
170
    {
171
        return 'KunstmaanTranslatorBundle:Index';
172
    }
173
174
    /**
175
     * @return QueryBuilder|null
176
     */
177
    public function getQueryBuilder()
178
    {
179
        if (\is_null($this->queryBuilder)) {
180
            $this->queryBuilder = new QueryBuilder($this->connection);
181
            $this->queryBuilder
182
                ->select('DISTINCT b.translation_id AS id, b.keyword, b.domain, b.status')
183
                ->from('kuma_translation', 'b')
184
                ->andWhere('b.status != :statusstring')
185
                ->setParameter('statusstring', Translation::STATUS_DISABLED);
186
187
            // Apply filters
188
            $filters = $this->getFilterBuilder()->getCurrentFilters();
189
            $locales = [];
190
191
            $textValue = $textComparator = null;
192
            foreach ($filters as $filter) {
193
                if ($filter->getType() instanceof EnumerationFilterType && $filter->getColumnName() == 'locale') {
194
                    // Override default enumeration filter handling ... catch selected locales here
195
                    $data = $filter->getData();
196
                    $comparator = $filter->getType()->getComparator();
197
                    if ($comparator == 'in') {
198
                        $locales = $data['value'];
199
                    } elseif ($comparator == 'notin') {
200
                        $locales = array_diff($this->locales, $data['value']);
201
                    }
202
                } elseif ($filter->getType() instanceof StringFilterType && $filter->getColumnName() == 'text') {
203
                    // Override default text filter handling ...
204
                    $data = $filter->getData();
205
                    $textValue = $data['value'];
206
                    $textComparator = $data['comparator'];
207
                } else {
208
                    /* @var AbstractDBALFilterType $type */
209
                    $type = $filter->getType();
210
                    $type->setQueryBuilder($this->queryBuilder);
211
                    $filter->apply();
212
                }
213
            }
214
215
            if (!empty($locales)) {
216
                $this->locales = $locales;
217
            }
218
            $this->locales = array_unique($this->locales);
219
220
            // Field building hack...
221
            foreach ($this->locales as $locale) {
222
                $this->addField($locale, strtoupper($locale), false, '@KunstmaanTranslator/Translator/inline_edit.html.twig');
223
            }
224
225
            // Field filter hack...
226
            $this->addFilter('locale', new EnumerationFilterType('locale'), 'kuma_translator.adminlist.filter.locale', array_combine(
227
                $this->locales,
228
                $this->locales
229
            ));
230
231
            // Add join for every locale
232
            foreach ($this->locales as $locale) {
233
                $this->queryBuilder->addSelect('t_'.$locale.'.`text` AS '.$locale);
234
                $this->queryBuilder->addSelect('t_'.$locale.'.id AS '.$locale.'_id');
235
                $this->queryBuilder->leftJoin(
236
                    'b',
237
                    'kuma_translation',
238
                    't_'.$locale,
239
                    'b.keyword = t_'.$locale.'.keyword and b.domain = t_'.$locale.'.domain and t_'.$locale.'.locale=:locale_'.$locale
240
                );
241
                $this->queryBuilder->setParameter('locale_'.$locale, $locale);
242
            }
243
244
            // Apply text filter
245
            if (!\is_null($textValue) && !\is_null($textComparator)) {
246
                $orX = $this->queryBuilder->expr()->orX();
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\DBAL\Query\Expr...xpressionBuilder::orX() has been deprecated with message: Use `or()` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
247
248
                foreach ($this->locales as $key => $locale) {
249
                    $uniqueId = 'txt_'.$key;
250
                    $expr = null;
251
                    switch ($textComparator) {
252
                        case 'equals':
253
                            $expr = $this->queryBuilder->expr()->eq('t_'.$locale.'.`text`', ':var_'.$uniqueId);
254
                            $this->queryBuilder->setParameter('var_'.$uniqueId, $textValue);
255
256
                            break;
257
                        case 'notequals':
258
                            $expr = $this->queryBuilder->expr()->neq('t_'.$locale.'.`text`', ':var_'.$uniqueId);
259
                            $this->queryBuilder->setParameter('var_'.$uniqueId, $textValue);
260
261
                            break;
262 View Code Duplication
                        case 'contains':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
263
                            $expr = $this->queryBuilder->expr()->like('t_'.$locale.'.`text`', ':var_'.$uniqueId);
264
                            $this->queryBuilder->setParameter('var_'.$uniqueId, '%'.$textValue.'%');
265
266
                            break;
267 View Code Duplication
                        case 'doesnotcontain':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
268
                            $expr = 't_'.$locale.'.`text`'.' NOT LIKE :var_'.$uniqueId;
269
                            $this->queryBuilder->setParameter('var_'.$uniqueId, '%'.$textValue.'%');
270
271
                            break;
272
                        case 'startswith':
273
                            $expr = $this->queryBuilder->expr()->like('t_'.$locale.'.`text`', ':var_'.$uniqueId);
274
                            $this->queryBuilder->setParameter('var_'.$uniqueId, $textValue.'%');
275
276
                            break;
277
                        case 'endswith':
278
                            $expr = $this->queryBuilder->expr()->like('t_'.$locale.'.`text`', ':var_'.$uniqueId);
279
                            $this->queryBuilder->setParameter('var_'.$uniqueId, '%'.$textValue);
280
281
                            break;
282
                        case 'empty':
283
                            $expr = $this->queryBuilder->expr()->orX(
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\DBAL\Query\Expr...xpressionBuilder::orX() has been deprecated with message: Use `or()` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
284
                                $this->queryBuilder->expr()->isNull('t_'.$locale.'.`text`'),
285
                                $this->queryBuilder->expr()->eq('t_'.$locale.'.`text`', '\'-\''),
286
                                $this->queryBuilder->expr()->eq('t_'.$locale.'.`text`', '\'\'')
287
                            );
288
289
                            break;
290
                    }
291
292
                    if (null !== $expr) {
293
                        $orX->add($expr);
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\DBAL\Query\Expr...positeExpression::add() has been deprecated with message: This class will be made immutable. Use with() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
294
                    }
295
                }
296
297
                $this->queryBuilder->andWhere($orX);
298
            }
299
300
            // Apply sorting
301 View Code Duplication
            if (!empty($this->orderBy)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
302
                $orderBy = $this->orderBy;
303
                $this->queryBuilder->orderBy($orderBy, ($this->orderDirection == 'DESC' ? 'DESC' : 'ASC'));
304
            }
305
        }
306
307
        return $this->queryBuilder;
308
    }
309
}
310