GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 597d51...e95e7a )
by Alex
01:49
created

ImportableAdminTrait::nearest()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.8977
c 0
b 0
f 0
cc 6
nc 6
nop 4
1
<?php
2
3
namespace Sigmapix\Sonata\ImportBundle\Admin;
4
5
use Port\Steps\Step\ValueConverterStep;
6
use Port\Steps\StepAggregator;
7
use Port\ValueConverter\DateTimeValueConverter;
8
use Sigmapix\Sonata\ImportBundle\Form\Type\ImportFieldChoiceType;
9
use Sonata\AdminBundle\Admin\AbstractAdmin;
10
use Sonata\AdminBundle\Admin\Pool;
11
use Sonata\AdminBundle\Builder\FormContractorInterface;
12
use Sonata\AdminBundle\Form\FormMapper;
13
use Sonata\AdminBundle\Route\RouteCollection;
14
use Sonata\DoctrineORMAdminBundle\Admin\FieldDescription;
15
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
18
use Symfony\Component\Form\Form;
19
use Symfony\Component\Form\FormBuilder;
20
use Symfony\Component\Form\FormBuilderInterface;
21
use Symfony\Component\HttpFoundation\File\UploadedFile;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpFoundation\Response;
24
use Symfony\Component\Translation\TranslatorInterface;
25
26
/**
27
 * Trait ImportableAdminTrait
28
 * @package Sigmapix\Sonata\ImportBundle\Admin
29
 */
30
trait ImportableAdminTrait
31
{
32
    /**
33
     * Options to set to the form (ie, validation_groups).
34
     *
35
     * @var array
36
     */
37
    protected $formOptions = [];
38
    /**
39
     * @var Form
40
     */
41
    private $importForm;
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    abstract public function getClass();
47
48
    /**
49
     * @return Pool
50
     */
51
    abstract public function getConfigurationPool();
52
53
    /**
54
     * @return FormContractorInterface
55
     */
56
    abstract public function getFormContractor();
57
58
    /**
59
     * {@inheritdoc}
60
     *
61
     * @throws \ReflectionException
62
     */
63
    public function getImportFormBuilder(array $headers)
64
    {
65
        $class = $this->hasActiveSubClass() ? $this->getActiveSubClass() : $this->getClass();
0 ignored issues
show
Bug introduced by
It seems like hasActiveSubClass() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
It seems like getActiveSubClass() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
66
        if ((new \ReflectionClass($class))->isAbstract()) {
67
            // If $class is Abstract, then use the first one.
68
            // Developers should then instantiate the good class by overriding DoctrineWrite::writeItem()
69
            $class = array_values($this->getSubClasses())[0];
0 ignored issues
show
Bug introduced by
It seems like getSubClasses() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
70
        }
71
72
        $this->formOptions['data_class'] = $class;
73
74
        $formBuilder = $this->getFormContractor()->getFormBuilder(
75
            'import_form', $this->formOptions
76
        );
77
78
        $this->defineImportFormBuilder($formBuilder, $headers);
79
80
        return $formBuilder;
81
    }
82
83
    /**
84
     * @param FormBuilderInterface $formBuilder
85
     * @param array $headers
86
     * todo: use defineFormBuilder for import Action and upload Action
87
     */
88
    public function defineImportFormBuilder(FormBuilderInterface $formBuilder, array $headers)
89
    {
90
        /** @var AbstractAdmin $this */
91
        $mapper = new FormMapper($this->getFormContractor(), $formBuilder, $this);
92
        $this->configureImportFields($mapper);
0 ignored issues
show
Bug introduced by
The method configureImportFields() does not exist on Sonata\AdminBundle\Admin\AbstractAdmin. Did you maybe mean configure()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
93
        /** @var ContainerInterface $container */
94
        $container = $this->getConfigurationPool()->getContainer();
95
        $trans = $container->get('translator');
96
97
        $oldValue = ini_get('mbstring.substitute_character');
98
        ini_set('mbstring.substitute_character', 'none');
99
        foreach ($formBuilder as $field) {
100
            /* @var FormBuilder $field */
101
            if ($field->getType()->getInnerType() instanceof EntityType) {
102
                continue;
103
            }
104
            $propertyPath = $field->getPropertyPath();
105
            if ($propertyPath && $propertyPath->getLength() > 1) {
106
                $mapper->add(
107
                    (string) $propertyPath, ImportFieldChoiceType::class, [
108
                    'choices' => $headers,
109
                    'data' => $this->nearest($field->getOption('label'), $headers, $trans),
0 ignored issues
show
Bug introduced by
The method nearest() does not seem to exist on object<Sonata\AdminBundle\Admin\AbstractAdmin>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
110
                    'mapped' => false,
111
                    'label' => $field->getOption('label')
112
                ]);
113
            } elseif ((string) $propertyPath === 'id') {
114
                $mapper->add($field->getName(), ImportFieldChoiceType::class, [
115
                    'choices' => $headers,
116
                    'data' => $this->nearest($field->getOption('label'), $headers, $trans),
0 ignored issues
show
Bug introduced by
The method nearest() does not seem to exist on object<Sonata\AdminBundle\Admin\AbstractAdmin>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
117
                    'mapped' => false,
118
                    'label' => $field->getOption('label')
119
                ]);
120
            } else {
121
                $mapper->add($field->getName(), ImportFieldChoiceType::class, [
122
                    'choices' => $headers,
123
                    'data' => $this->nearest($field->getOption('label'), $headers, $trans, $field->getOption('translation_domain')),
0 ignored issues
show
Bug introduced by
The method nearest() does not seem to exist on object<Sonata\AdminBundle\Admin\AbstractAdmin>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
124
                    'mapped' => $field->getOption('mapped'),
125
                    'label' => $field->getOption('label'),
126
                    'label_format' => $field->getOption('label_format'), // This will be used for DateTimeConverter
127
                    'translation_domain' => $field->getOption('translation_domain')
128
                ]);
129
            }
130
        }
131
        ini_set('mbstring.substitute_character', $oldValue);
132
        $formBuilder->add('import', SubmitType::class);
133
        $this->attachInlineValidator();
0 ignored issues
show
Bug introduced by
The method attachInlineValidator() cannot be called from this context as it is declared protected in class Sonata\AdminBundle\Admin\AbstractAdmin.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
134
    }
135
136
    /**
137
     * @param $admin
138
     * @param null $object
139
     * @return mixed
140
     */
141
    public function configureActionButtons($admin, $object = null)
142
    {
143
        $buttonList = parent::configureActionButtons($admin, $object);
144
        $buttonList['import'] = [
145
            'template' => 'SigmapixSonataImportBundle:Button:import_button.html.twig'
146
        ];
147
        return $buttonList;
148
    }
149
150
    /**
151
     * @param array $headers
152
     * @return Form
153
     * @throws \ReflectionException
154
     */
155
    public function getImportForm(array $headers)
156
    {
157
        $this->buildImportForm($headers);
158
        return $this->importForm;
159
    }
160
161
    /**
162
     * @param StepAggregator $workflow
163
     */
164
    public function configureImportSteps(StepAggregator $workflow)
165
    {
166
        $dateTimeFields = [];
167
        foreach ($this->importForm as $f) {
168
            /** @var Form $f */
169
            /** @var FieldDescription $fieldOptions */
170
            $fieldOptions = $f->getConfig()->getOption('sonata_field_description');
171
            if ($fieldOptions && ('datetime' === $fieldOptions->getMappingType() || 'date' === $fieldOptions->getMappingType() || $f->getConfig()->getOption('label_format'))) {
172
                $dateTimeFields[$f->getName()] = $f->getConfig()->getOption('label_format');
173
            }
174
        }
175
        $converterStep = new ValueConverterStep();
176
        foreach ($dateTimeFields as $dateTimeField => $dateTimeFormat) {
177
            $converter = new DateTimeValueConverter($dateTimeFormat);
178
            $converterStep->add('['.$dateTimeField.']', $converter);
179
        }
180
        $workflow->addStep($converterStep);
181
    }
182
183
    /**
184
     * This method can be overloaded in your Admin service.
185
     * It's called from importAction.
186
     *
187
     * @param Request $request
188
     * @param Form    $form
189
     *
190
     * @return Response|null
191
     */
192
    public function preImport(Request $request, Form $form)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $form is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
193
    {
194
    }
195
196
    /**
197
     * This method can be overloaded in your Admin service.
198
     * It's called from importAction.
199
     *
200
     * @param Request      $request
201
     * @param UploadedFile $file
202
     * @param Form         $form
203
     * @param mixed        $results
204
     *
205
     * @return Response|null
206
     */
207
    public function postImport(Request $request, UploadedFile $file, Form $form, $results)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $file is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $form is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $results is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
208
    {
209
    }
210
211
    /**
212
     * @param FormMapper $formMapper
213
     */
214
    abstract protected function configureImportFields(FormMapper $formMapper);
215
216
    /**
217
     * Attach the inline validator to the model metadata, this must be done once per admin.
218
     */
219
    abstract protected function attachInlineValidator();
220
221
    /**
222
     * @param RouteCollection $collection
223
     */
224
    protected function configureRoutes(RouteCollection $collection)
225
    {
226
        /* @var AbstractAdmin $this */
227
        $collection
228
                ->add('import', 'upload/{fileName}')
229
                ->add('upload')
230
        ;
231
    }
232
233
    /**
234
     * @param array $headers
235
     * @throws \ReflectionException
236
     */
237
    protected function buildImportForm(array $headers)
238
    {
239
        if ($this->importForm) {
240
            return;
241
        }
242
        $this->importForm = $this->getImportFormBuilder($headers)->getForm();
243
    }
244
245
    /**
246
     * @param $input
247
     * @param $words
248
     * @param TranslatorInterface $trans
249
     * @param string $domain
250
     * @return string
251
     */
252
    private function nearest($input, $words, TranslatorInterface $trans, $domain = null)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
253
    {
254
        // TODO $input should be the $field, to try both 'name' and 'propertyPath' attributes
255
        $domain = $domain ?: 'messages';
256
        $closest = '';
257
        $shortest = -1;
258
259
        foreach ($words as $word) {
260
            $wordASCII = mb_convert_encoding($word, 'ASCII');
261
            $lev = levenshtein($input, $wordASCII);
262
            $levCase = levenshtein(strtolower($input), strtolower($wordASCII));
263
            $levTrans = levenshtein($trans->trans($input, [], $domain), $wordASCII);
264
            $lev = min([$lev, $levCase, $levTrans]);
265
            if ($lev === 0) {
266
                $closest = $word;
267
                break;
268
            }
269
            if ($lev <= $shortest || $shortest < 0) {
270
                $closest = $word;
271
                $shortest = $lev;
272
            }
273
        }
274
275
        return $closest;
276
    }
277
}
278