SonataImportCommand::execute()   F
last analyzed

Complexity

Conditions 19
Paths 3940

Size

Total Lines 130
Code Lines 80

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 19
eloc 80
c 1
b 0
f 0
nc 3940
nop 2
dl 0
loc 130
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Doctrs\SonataImportBundle\Command;
4
5
use Doctrine\ORM\EntityManager;
0 ignored issues
show
Bug introduced by
The type Doctrine\ORM\EntityManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Doctrine\ORM\ORMException;
0 ignored issues
show
Bug introduced by
The type Doctrine\ORM\ORMException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Doctrs\SonataImportBundle\Entity\UploadFile;
8
use Doctrs\SonataImportBundle\Entity\ImportLog;
9
use Doctrs\SonataImportBundle\Loaders\CsvFileLoader;
10
use Doctrs\SonataImportBundle\Loaders\FileLoaderInterface;
11
use Doctrs\SonataImportBundle\Service\SonataImportType\AdminAbstractAwareInterface;
12
use Doctrs\SonataImportBundle\Service\SonataImportType\FormBuilderAwareInterface;
13
use Doctrs\SonataImportBundle\Service\SonataImportType\ImportInterface;
14
use Sonata\AdminBundle\Admin\AbstractAdmin;
15
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
16
use Symfony\Component\Console\Exception\InvalidArgumentException;
17
use Symfony\Component\Console\Input\InputArgument;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Form\FormBuilderInterface;
21
use Symfony\Component\HttpFoundation\File\File;
22
23
class SonataImportCommand extends ContainerAwareCommand {
24
25
    /** @var EntityManager $this->em  */
26
    protected $em;
27
28
    protected function configure() {
29
        $this
30
            ->setName('doctrs:sonata:import')
31
            ->setDescription('Import data to sonata from CSV')
32
            ->addArgument('csv_file', InputArgument::REQUIRED, 'id UploadFile entity')
33
            ->addArgument('admin_code', InputArgument::REQUIRED, 'code to sonata admin bundle')
34
            ->addArgument('encode', InputArgument::OPTIONAL, 'file encode')
35
            ->addArgument('file_loader', InputArgument::OPTIONAL, 'number of loader class')
36
        ;
37
    }
38
39
    protected function execute(InputInterface $input, OutputInterface $output) {
40
41
        $this->em = $this->getContainer()->get('doctrine')->getManager();
42
        $uploadFileId = $input->getArgument('csv_file');
43
        $adminCode = $input->getArgument('admin_code');
44
        $encode = strtolower($input->getArgument('encode'));
45
        $fileLoaderId = $input->getArgument('file_loader');
46
47
        /** @var UploadFile $uploadFile */
48
        $uploadFile = $this->em->getRepository('DoctrsSonataImportBundle:UploadFile')->find($uploadFileId);
49
        $fileLoaders = $this->getContainer()->getParameter('doctrs_sonata_import.class_loaders');
50
        $fileLoader = isset($fileLoaders[$fileLoaderId], $fileLoaders[$fileLoaderId]['class']) ?
51
            $fileLoaders[$fileLoaderId]['class'] : null;
52
53
        if (!class_exists($fileLoader)) {
54
            $uploadFile->setStatusError('class_loader not found');
55
            $this->em->flush($uploadFile);
56
            return;
57
        }
58
        $fileLoader = new $fileLoader();
59
        if (!$fileLoader instanceof FileLoaderInterface) {
60
            $uploadFile->setStatusError('class_loader must be instanceof "FileLoaderInterface"');
61
            $this->em->flush($uploadFile);
62
            return;
63
        }
64
65
        try {
66
            $fileLoader->setFile(new File($uploadFile->getFile()));
67
68
            $pool = $this->getContainer()->get('sonata.admin.pool');
69
            /** @var AbstractAdmin $instance */
70
            $instance = $pool->getInstance($adminCode);
71
            $entityClass = $instance->getClass();
72
            $meta = $this->em->getClassMetadata($entityClass);
73
            $identifier = $meta->getSingleIdentifierFieldName();
74
            $exportFields = $instance->getExportFields();
75
            $form = $instance->getFormBuilder();
76
            foreach ($fileLoader->getIteration() as $line => $data) {
77
78
                $log = new ImportLog();
79
                $log
80
                    ->setLine($line)
81
                    ->setUploadFile($uploadFile)
82
                ;
83
84
                $entity = new $entityClass();
85
                $errors = [];
86
                foreach ($exportFields as $key => $name) {
87
                    $value = isset($data[$key]) ? $data[$key] : '';
88
89
                    /**
90
                     * В случае если указан ID (первый столбец)
91
                     * ищем сущность в базе
92
                     */
93
                    if ($name === $identifier) {
94
                        if ($value) {
95
                            $oldEntity = $instance->getObject($value);
96
                            if ($oldEntity) {
97
                                $entity = $oldEntity;
98
                            }
99
                        }
100
                        continue;
101
                    }
102
                    /**
103
                     * Поля форм не всегда соответствуют тому, что есть на сайте, и что в админке
104
                     * Поэтому если поле не указано в админке, то просто пропускаем его
105
                     */
106
                    if (!$form->has($name)) {
107
                        continue;
108
                    }
109
                    $formBuilder = $form->get($name);
110
                    /**
111
                     * Многие делают ошибки в стандартной кодировке,
112
                     * поэтому на всякий случай провверяем оба варианта написания
113
                     */
114
                    if ($encode !== 'utf8' && $encode !== 'utf-8') {
115
                        $value = iconv($encode, 'utf8//TRANSLIT', $value);
116
                    }
117
                    try {
118
                        $method = $this->getSetMethod($name);
119
                        $entity->$method($this->getValue($value, $formBuilder, $instance));
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on Doctrs\SonataImportBundl...and\SonataImportCommand. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

119
                        $entity->$method($this->/** @scrutinizer ignore-call */ getValue($value, $formBuilder, $instance));

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...
120
                    } catch (\Exception $e) {
121
                        $errors[] = $e->getMessage();
122
                        break;
123
                    }
124
125
                }
126
                if (!count($errors)) {
127
                    $validator = $this->getContainer()->get('validator');
128
                    $errors = $validator->validate($entity);
129
                }
130
131
                if (!count($errors)) {
132
                    $idMethod = $this->getSetMethod($identifier, 'get');
133
                    /**
134
                     * Если у сущности нет ID, то она новая - добавляем ее
135
                     */
136
                    if (!$entity->$idMethod()) {
137
                        $this->em->persist($entity);
138
                        $log->setStatus(ImportLog::STATUS_SUCCESS);
139
                    } else {
140
                        $log->setStatus(ImportLog::STATUS_EXISTS);
141
                    }
142
                    $this->em->flush($entity);
143
                    $log->setForeignId($entity->$idMethod());
144
                } else {
145
                    $log->setMessage(json_encode($errors));
146
                    $log->setStatus(ImportLog::STATUS_ERROR);
147
                }
148
                $this->em->persist($log);
149
                $this->em->flush($log);
150
            }
151
            $uploadFile->setStatus(UploadFile::STATUS_SUCCESS);
152
            $this->em->flush($uploadFile);
153
        } catch (\Exception $e) {
154
            /**
155
             * Данный хак нужен в случае бросания ORMException
156
             * В случае бросания ORMException entity manager останавливается
157
             * и его требуется перезагрузить
158
             */
159
            if (!$this->em->isOpen()) {
160
                $this->em = $this->em->create(
161
                    $this->em->getConnection(),
162
                    $this->em->getConfiguration()
163
                );
164
                $uploadFile = $this->em->getRepository('DoctrsSonataImportBundle:UploadFile')->find($uploadFileId);
165
            }
166
167
            $uploadFile->setStatusError($e->getMessage());
168
            $this->em->flush($uploadFile);
169
        }
170
    }
171
172
    protected function getSetMethod($name, $method = 'set') {
173
        return $method . str_replace(' ', '', ucfirst(join('', explode('_', $name))));
174
    }
175
176
    protected function setValue($value, FormBuilderInterface $formBuilder, AbstractAdmin $admin) {
177
178
        $mappings = $this->getContainer()->getParameter('doctrs_sonata_import.mappings');
179
        $type = $formBuilder->getType()->getName();
0 ignored issues
show
Bug introduced by
The method getName() does not exist on Symfony\Component\Form\ResolvedFormTypeInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

179
        $type = $formBuilder->getType()->/** @scrutinizer ignore-call */ getName();

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...
180
181
        /**
182
         * Проверяем кастомные типы форм на наличие в конфиге.
183
         * В случае совпадения, получаем значение из класса, указанного в конфиге
184
         */
185
        foreach ($mappings as $item) {
186
            if ($item['name'] === $type) {
187
                if ($this->getContainer()->has($item['class']) && $this->getContainer()->get($item['class']) instanceof ImportInterface) {
188
                    /** @var ImportInterface $class */
189
190
                    $class = $this->getContainer()->get($item['class']);
191
192
                    if ($class instanceof AdminAbstractAwareInterface) {
193
                        $class->setAdminAbstract($admin);
194
                    }
195
                    if ($class instanceof FormBuilderAwareInterface) {
196
                        $class->setFormBuilder($formBuilder);
197
                    }
198
199
                    return $class->getFormatValue($value);
200
                }
201
            }
202
        }
203
204
        return (string)$value;
205
    }
206
}
207