Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Faker\ORM\Doctrine;
4
 
5
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
6
use Doctrine\Common\Persistence\ObjectManager;
7
 
8
require_once 'backward-compatibility.php';
9
 
10
/**
11
 * Service class for populating a table through a Doctrine Entity class.
12
 */
13
class EntityPopulator
14
{
15
    /**
16
     * @var ClassMetadata
17
     */
18
    protected $class;
19
    /**
20
     * @var array
21
     */
22
    protected $columnFormatters = [];
23
    /**
24
     * @var array
25
     */
26
    protected $modifiers = [];
27
 
28
    public function __construct(ClassMetadata $class)
29
    {
30
        $this->class = $class;
31
    }
32
 
33
    /**
34
     * @return string
35
     */
36
    public function getClass()
37
    {
38
        return $this->class->getName();
39
    }
40
 
41
    public function setColumnFormatters($columnFormatters)
42
    {
43
        $this->columnFormatters = $columnFormatters;
44
    }
45
 
46
    /**
47
     * @return array
48
     */
49
    public function getColumnFormatters()
50
    {
51
        return $this->columnFormatters;
52
    }
53
 
54
    public function mergeColumnFormattersWith($columnFormatters)
55
    {
56
        $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
57
    }
58
 
59
    public function setModifiers(array $modifiers)
60
    {
61
        $this->modifiers = $modifiers;
62
    }
63
 
64
    /**
65
     * @return array
66
     */
67
    public function getModifiers()
68
    {
69
        return $this->modifiers;
70
    }
71
 
72
    public function mergeModifiersWith(array $modifiers)
73
    {
74
        $this->modifiers = array_merge($this->modifiers, $modifiers);
75
    }
76
 
77
    /**
78
     * @return array
79
     */
80
    public function guessColumnFormatters(\Faker\Generator $generator)
81
    {
82
        $formatters = [];
83
        $nameGuesser = new \Faker\Guesser\Name($generator);
84
        $columnTypeGuesser = new ColumnTypeGuesser($generator);
85
 
86
        foreach ($this->class->getFieldNames() as $fieldName) {
87
            if ($this->class->isIdentifier($fieldName) || !$this->class->hasField($fieldName)) {
88
                continue;
89
            }
90
 
91
            $size = $this->class->fieldMappings[$fieldName]['length'] ?? null;
92
 
93
            if ($formatter = $nameGuesser->guessFormat($fieldName, $size)) {
94
                $formatters[$fieldName] = $formatter;
95
 
96
                continue;
97
            }
98
 
99
            if ($formatter = $columnTypeGuesser->guessFormat($fieldName, $this->class)) {
100
                $formatters[$fieldName] = $formatter;
101
 
102
                continue;
103
            }
104
        }
105
 
106
        foreach ($this->class->getAssociationNames() as $assocName) {
107
            if ($this->class->isCollectionValuedAssociation($assocName)) {
108
                continue;
109
            }
110
 
111
            $relatedClass = $this->class->getAssociationTargetClass($assocName);
112
 
113
            $unique = $optional = false;
114
 
115
            if ($this->class instanceof \Doctrine\ORM\Mapping\ClassMetadata) {
116
                $mappings = $this->class->getAssociationMappings();
117
 
118
                foreach ($mappings as $mapping) {
119
                    if ($mapping['targetEntity'] == $relatedClass) {
120
                        if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_ONE) {
121
                            $unique = true;
122
                            $optional = $mapping['joinColumns'][0]['nullable'] ?? false;
123
 
124
                            break;
125
                        }
126
                    }
127
                }
128
            } elseif ($this->class instanceof \Doctrine\ODM\MongoDB\Mapping\ClassMetadata) {
129
                $mappings = $this->class->associationMappings;
130
 
131
                foreach ($mappings as $mapping) {
132
                    if ($mapping['targetDocument'] == $relatedClass) {
133
                        if ($mapping['type'] == \Doctrine\ODM\MongoDB\Mapping\ClassMetadata::ONE && $mapping['association'] == \Doctrine\ODM\MongoDB\Mapping\ClassMetadata::REFERENCE_ONE) {
134
                            $unique = true;
135
                            $optional = $mapping['nullable'] ?? false;
136
 
137
                            break;
138
                        }
139
                    }
140
                }
141
            }
142
 
143
            $index = 0;
144
            $formatters[$assocName] = static function ($inserted) use ($relatedClass, &$index, $unique, $optional, $generator) {
145
                if (isset($inserted[$relatedClass])) {
146
                    if ($unique) {
147
                        $related = null;
148
 
149
                        if (isset($inserted[$relatedClass][$index]) || !$optional) {
150
                            $related = $inserted[$relatedClass][$index];
151
                        }
152
 
153
                        ++$index;
154
 
155
                        return $related;
156
                    }
157
 
158
                    return $generator->randomElement($inserted[$relatedClass]);
159
                }
160
 
161
                return null;
162
            };
163
        }
164
 
165
        return $formatters;
166
    }
167
 
168
    /**
169
     * Insert one new record using the Entity class.
170
     *
171
     * @param bool $generateId
172
     *
173
     * @return EntityPopulator
174
     */
175
    public function execute(ObjectManager $manager, $insertedEntities, $generateId = false)
176
    {
177
        $obj = $this->class->newInstance();
178
 
179
        $this->fillColumns($obj, $insertedEntities);
180
        $this->callMethods($obj, $insertedEntities);
181
 
182
        if ($generateId) {
183
            $idsName = $this->class->getIdentifier();
184
 
185
            foreach ($idsName as $idName) {
186
                $id = $this->generateId($obj, $idName, $manager);
187
                $this->class->reflFields[$idName]->setValue($obj, $id);
188
            }
189
        }
190
 
191
        $manager->persist($obj);
192
 
193
        return $obj;
194
    }
195
 
196
    private function fillColumns($obj, $insertedEntities): void
197
    {
198
        foreach ($this->columnFormatters as $field => $format) {
199
            if (null !== $format) {
200
                // Add some extended debugging information to any errors thrown by the formatter
201
                try {
202
                    $value = is_callable($format) ? $format($insertedEntities, $obj) : $format;
203
                } catch (\InvalidArgumentException $ex) {
204
                    throw new \InvalidArgumentException(sprintf(
205
                        'Failed to generate a value for %s::%s: %s',
206
                        get_class($obj),
207
                        $field,
208
                        $ex->getMessage(),
209
                    ));
210
                }
211
                // Try a standard setter if it's available, otherwise fall back on reflection
212
                $setter = sprintf('set%s', ucfirst($field));
213
 
214
                if (is_callable([$obj, $setter])) {
215
                    $obj->$setter($value);
216
                } else {
217
                    $this->class->reflFields[$field]->setValue($obj, $value);
218
                }
219
            }
220
        }
221
    }
222
 
223
    private function callMethods($obj, $insertedEntities): void
224
    {
225
        foreach ($this->getModifiers() as $modifier) {
226
            $modifier($obj, $insertedEntities);
227
        }
228
    }
229
 
230
    /**
231
     * @return int
232
     */
233
    private function generateId($obj, $column, ObjectManager $manager)
234
    {
235
        $repository = $manager->getRepository(get_class($obj));
236
        $result = $repository->createQueryBuilder('e')
237
                ->select(sprintf('e.%s', $column))
238
                ->getQuery()
239
                ->execute();
240
        $ids = array_map('current', $result->toArray());
241
 
242
        do {
243
            $id = mt_rand();
244
        } while (in_array($id, $ids, false));
245
 
246
        return $id;
247
    }
248
}