Completed
Push — master ( a46bcd...68aa75 )
by Jan
03:05
created

EntityImporter::configureOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * part-db version 0.1
5
 * Copyright (C) 2005 Christoph Lechner
6
 * http://www.cl-projects.de/
7
 *
8
 * part-db version 0.2+
9
 * Copyright (C) 2009 K. Jacobs and others (see authors.php)
10
 * http://code.google.com/p/part-db/
11
 *
12
 * Part-DB Version 0.4+
13
 * Copyright (C) 2016 - 2019 Jan Böhmer
14
 * https://github.com/jbtronics
15
 *
16
 * This program is free software; you can redistribute it and/or
17
 * modify it under the terms of the GNU General Public License
18
 * as published by the Free Software Foundation; either version 2
19
 * of the License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
29
 *
30
 */
31
32
namespace App\Services;
33
34
35
use App\Entity\StructuralDBElement;
36
use Doctrine\ORM\EntityManagerInterface;
37
use Symfony\Bundle\MakerBundle\Str;
38
use Symfony\Component\HttpFoundation\File\File;
39
use Symfony\Component\OptionsResolver\OptionsResolver;
40
use Symfony\Component\Serializer\SerializerInterface;
41
use Symfony\Component\Validator\Validator\ValidatorInterface;
42
43
class EntityImporter
44
{
45
46
    protected $serializer;
47
    protected $em;
48
    protected $validator;
49
50
    public function __construct(SerializerInterface $serializer, EntityManagerInterface $em, ValidatorInterface $validator)
51
    {
52
        $this->serializer = $serializer;
53
        $this->em = $em;
54
        $this->validator = $validator;
55
    }
56
57
    protected function configureOptions(OptionsResolver $resolver)
58
    {
59
        $resolver->setDefaults([
60
           'csv_separator' => ';',
61
            'format' => 'json',
62
            'preserve_children' => true,
63
            'parent' => null,
64
            'abort_on_validation_error' => true
65
        ]);
66
    }
67
68
    /**
69
     * This methods deserializes the given file and saves it database.
70
     * The imported elements will be checked (validated) before written to database.
71
     * @param File $file The file that should be used for importing.
72
     * @param string $class_name The class name of the enitity that should be imported.
73
     * @param array $options Options for the import process.
74
     * @return array An associative array containing an ConstraintViolationList and the entity name as key are returned,
75
     * if an error happened during validation. When everything was successfull, the array should be empty.
76
     */
77
    public function fileToDBEntities(File $file, string $class_name, array $options = []) : array
78
    {
79
        $resolver = new OptionsResolver();
80
        $this->configureOptions($resolver);
81
82
        $options = $resolver->resolve($options);
83
84
85
        $entities = $this->fileToEntityArray($file, $class_name, $options);
86
87
        $errors = array();
88
89
        //Iterate over each $entity write it to DB.
90
        foreach ($entities as $entity) {
91
            /** @var StructuralDBElement $entity */
92
            //Move every imported entity to the selected parent
93
            $entity->setParent($options['parent']);
94
95
            //Validate entity
96
            $tmp = $this->validator->validate($entity);
97
98
            //When no validation error occured, persist entity to database (cascade must be set in entity)
99
            if ($tmp === null) {
100
                $this->em->persist($entity);
101
            } else { //Log validation errors to global log.
102
                $errors[$entity->getFullPath()] = $tmp;
103
            }
104
        }
105
106
        //Save changes to database, when no error happened, or we should continue on error.
107
        if (empty($errors) || $options['abort_on_validation_error'] == false) {
108
            $this->em->flush();
109
        }
110
111
        return $errors;
112
    }
113
114
    /**
115
     * This method converts (deserialize) a (uploaded) file to an array of entities with the given class.
116
     *
117
     * The imported elements will NOT be validated. If you want to use the result array, you have to validate it by yourself.
118
     * @param File $file The file that should be used for importing.
119
     * @param string $class_name The class name of the enitity that should be imported.
120
     * @param array $options Options for the import process.
121
     * @return array An array containing the deserialized elements.
122
     */
123
    public function fileToEntityArray(File $file, string $class_name, array $options = []) : array
124
    {
125
        $resolver = new OptionsResolver();
126
        $this->configureOptions($resolver);
127
128
        $options = $resolver->resolve($options);
129
130
        //Read file contents
131
        $content = file_get_contents($file->getRealPath());
132
133
        $groups = ['simple'];
134
        //Add group when the children should be preserved
135
        if ($options['preserve_children']) {
136
            $groups[] = 'include_children';
137
        }
138
139
        //The [] behind class_name denotes that we expect an array.
140
        $entities = $this->serializer->deserialize($content, $class_name . '[]', $options['format'], ['groups' => $groups]);
141
142
        //Ensure we have an array of entitity elements.
143
        if(!is_array($entities)) {
0 ignored issues
show
introduced by
The condition is_array($entities) is always false.
Loading history...
144
            $entities = [$entities];
145
        }
146
147
        //The serializer has only set the children attributes. We also have to change the parent value (the real value in DB)
148
        if ($entities[0] instanceof StructuralDBElement) {
149
            $this->correctParentEntites($entities, null);
150
        }
151
152
        return $entities;
153
    }
154
155
    /**
156
     * This functions corrects the parent setting based on the children value of the parent.
157
     * @param iterable $entities The list of entities that should be fixed.
158
     * @param null $parent The parent, to which the entity should be set.
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $parent is correct as it would always require null to be passed?
Loading history...
159
     */
160
    protected function correctParentEntites(iterable $entities, $parent = null)
161
    {
162
        foreach ($entities as $entity) {
163
            /** @var $entity StructuralDBElement */
164
            $entity->setParent($parent);
165
            //Do the same for the children of entity
166
            $this->correctParentEntites($entity->getChildren(), $entity);
167
        }
168
    }
169
}