Passed
Push — master ( f6a24d...21e5a4 )
by Oleg
03:36
created

SonataImportCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
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
66
        try {
67
            $fileLoader->setFile(new File($uploadFile->getFile()));
68
69
            $pool = $this->getContainer()->get('sonata.admin.pool');
70
            /** @var AbstractAdmin $instance */
71
            $instance = $pool->getInstance($adminCode);
72
            $entityClass = $instance->getClass();
73
            $meta = $this->em->getClassMetadata($entityClass);
74
            $identifier = $meta->getSingleIdentifierFieldName();
75
            $exportFields = $instance->getExportFields();
76
            $form = $instance->getFormBuilder();
77
            foreach ($fileLoader->getIteration() as $line => $data) {
78
79
                $log = new ImportLog();
80
                $log
81
                    ->setLine($line)
82
                    ->setUploadFile($uploadFile)
83
                ;
84
85
                $entity = new $entityClass();
86
                $errors = [];
87
                foreach ($exportFields as $key => $name) {
88
                    $value = isset($data[$key]) ? $data[$key] : '';
89
90
                    /**
91
                     * В случае если указан ID (первый столбец)
92
                     * ищем сущность в базе
93
                     */
94
                    if ($name === $identifier) {
95
                        if ($value) {
96
                            $oldEntity = $instance->getObject($value);
97
                            if ($oldEntity) {
98
                                $entity = $oldEntity;
99
                            }
100
                        }
101
                        continue;
102
                    }
103
                    /**
104
                     * Поля форм не всегда соответствуют тому, что есть на сайте, и что в админке
105
                     * Поэтому если поле не указано в админке, то просто пропускаем его
106
                     */
107
                    if (!$form->has($name)) {
108
                        continue;
109
                    }
110
                    $formBuilder = $form->get($name);
111
                    /**
112
                     * Многие делают ошибки в стандартной кодировке,
113
                     * поэтому на всякий случай провверяем оба варианта написания
114
                     */
115
                    if ($encode !== 'utf8' && $encode !== 'utf-8') {
116
                        $value = iconv($encode, 'utf8//TRANSLIT', $value);
117
                    }
118
                    try {
119
                        $method = $this->getSetMethod($name);
120
                        $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

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

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