Test Failed
Pull Request — master (#1)
by Curtis
03:55
created

GenerateDataFactoryCommand::buildFactoryData()   D

Complexity

Conditions 30
Paths 108

Size

Total Lines 95
Code Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 76
dl 0
loc 95
rs 4.1
c 0
b 0
f 0
cc 30
nc 108
nop 1

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 DoctrineRepoHelper\Command;
4
5
6
use Doctrine\ORM\Mapping\ClassMetadata;
7
use Doctrine\ORM\EntityManagerInterface;
8
use Symfony\Component\Console\Command\Command;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use Zend\Code\Generator\DocBlockGenerator;
13
use Zend\Code\Generator\FileGenerator;
14
15
/**
16
 * Class GenerateDataFactoryCommand
17
 * @package DoctrineRepoHelper\Command
18
 */
19
class GenerateDataFactoryCommand extends Command
20
{
21
    /** @var EntityManagerInterface */
22
    protected $entityManager;
23
24
    /**
25
     * GenerateTraitCommand constructor.
26
     * @param EntityManagerInterface $entityManager
27
     */
28
    public function __construct(EntityManagerInterface $entityManager)
29
    {
30
        $this->entityManager = $entityManager;
31
        parent::__construct();
32
    }
33
34
    protected function configure()
35
    {
36
        parent::configure();
37
38
        $this
39
            ->setName('orm:generate-data-factories')
40
            ->setDescription('')
41
            ->setHelp('')
42
            ->addOption(
43
                'output',
44
                'o',
45
                InputOption::VALUE_OPTIONAL,
46
                'Output path',
47
                getcwd() . '/data/factories'
48
            )
49
            ->addOption(
50
                'force',
51
                'f',
52
                InputOption::VALUE_OPTIONAL,
53
                'Overwrite existing data factories'
54
            )
55
            ->addOption(
56
                'filter',
57
                null,
58
                InputOption::VALUE_OPTIONAL,
59
                'filter the list of entities data factories are created for'
60
            );
61
    }
62
63
    public function execute(InputInterface $input, OutputInterface $output)
64
    {
65
        $destination = $input->getOption('output');
66
        $metaDataEntries = $this->entityManager->getMetadataFactory()->getAllMetadata();
67
68
        if (!is_dir($destination)) {
0 ignored issues
show
Bug introduced by
It seems like $destination can also be of type string[]; however, parameter $filename of is_dir() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

68
        if (!is_dir(/** @scrutinizer ignore-type */ $destination)) {
Loading history...
69
            mkdir($destination, 0777, true);
0 ignored issues
show
Bug introduced by
It seems like $destination can also be of type string[]; however, parameter $pathname of mkdir() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

69
            mkdir(/** @scrutinizer ignore-type */ $destination, 0777, true);
Loading history...
70
        }
71
72
        /** @var ClassMetadata $metaData */
73
        foreach ($metaDataEntries as $metaData) {
74
            if ($filter = $input->getOption('filter')) {
75
                if (strpos($metaData->getName(), $filter) === false) {
76
                    continue;
77
                }
78
            }
79
80
            $fileName = $destination . '/' . $metaData->reflClass->getShortName() . 'DataFactory.php';
0 ignored issues
show
Bug introduced by
Accessing reflClass on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
81
            // TODO handle duplicate names
82
83
            $file = FileGenerator::fromArray(
84
                [
85
                    'docblock' => DocBlockGenerator::fromArray(
86
                        [
87
                            'shortDescription' => '',
88
                            'longDescription' => '',
89
                            'tags' => [
90
                                [
91
                                    'name' => 'var',
92
                                    'description' => '\\Codeception\\Module\\DataFactory $factory'
93
                                ],
94
                                [
95
                                    'name' => 'var',
96
                                    'description' => '\\Doctrine\\ORM\\EntityManager $em'
97
                                ]
98
                            ]
99
                        ]
100
                    ),
101
                    'body' => $this->buildBody($metaData),
102
                ]
103
            );
104
105
            file_put_contents($fileName, $file->generate());
106
        }
107
108
        $output->writeln(
109
            sprintf(
110
                'Data factories written to "%s"',
111
                $destination
0 ignored issues
show
Bug introduced by
It seems like $destination can also be of type string[]; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

111
                /** @scrutinizer ignore-type */ $destination
Loading history...
112
            )
113
        );
114
    }
115
116
    /**
117
     * @param ClassMetadata $metaData
118
     * @return string[]
119
     */
120
    private function buildFactoryData(ClassMetadata $metaData): array
121
    {
122
        $data = [];
123
124
        foreach ($metaData->fieldMappings as $fieldMapping) {
125
            switch ($fieldMapping['type']) {
126
                case 'smallint':
127
                case 'integer':
128
                case 'bigint':
129
                    $data[] = sprintf(
130
                        "        '%s' => random_int(0, 65000),\n",
131
                        $fieldMapping['fieldName']
132
                    );
133
                    break;
134
                case 'decimal':
135
                case 'float':
136
                    $data[] = sprintf(
137
                        "        '%s' => Faker::randomFloat(2),\n",
138
                        $fieldMapping['fieldName']
139
                    );
140
                    break;
141
                case 'string':
142
                    $data[] = sprintf(
143
                        "        '%s' => Faker::sentence(),\n",
144
                        $fieldMapping['fieldName']
145
                    );
146
                    break;
147
                case 'text':
148
                    $data[] = sprintf(
149
                        "        '%s' => Faker::paragraph(),\n",
150
                        $fieldMapping['fieldName']
151
                    );
152
                    break;
153
                case 'guid':
154
                    $data[] = sprintf(
155
                        "        '%s' => uniqid('', true)",
156
                        $fieldMapping['fieldName']
157
                    );
158
                    break;
159
                case 'binary':
160
                case 'blob':
161
                    break;
162
                case 'boolean':
163
                    $data[] = sprintf(
164
                        "        '%s' => (bool)random_int(0, 1),\n",
165
                        $fieldMapping['fieldName']
166
                    );
167
                    break;
168
                case 'date':
169
                case 'date_immutable':
170
                case 'datetime':
171
                case 'datetime_immutable':
172
                case 'datetimetz':
173
                case 'datetimetz_immutable':
174
                case 'time':
175
                case 'time_immutable':
176
                    $data[] = sprintf(
177
                        "        '%s' => Faker::dateTime(),\n",
178
                        $fieldMapping['fieldName']
179
                    );
180
                    break;
181
                case 'dateinterval':
182
                case 'array':
183
                case 'simple_array':
184
                case 'json':
185
                case 'json_array':
186
                case 'object':
187
                    break;
188
                default:
189
                    $data[] = sprintf(
190
                        "        '%s' => Faker::word(),\n",
191
                        $fieldMapping['fieldName']
192
                    );
193
                    break;
194
            }
195
        }
196
197
        foreach ($metaData->associationMappings as $associationMapping) {
198
            switch ($associationMapping['type']) {
199
                case 1:
200
                    $data[] = sprintf(
201
                        "        '%s' => 'entity|' . \\%s::class",
202
                        $associationMapping['fieldName'],
203
                        $associationMapping['targetEntity']
204
                    );
205
                    break;
206
                case 2:
207
                    // TODO many to one?
208
                    break;
209
                default:
210
                    break;
211
            }
212
        }
213
214
        return $data;
215
    }
216
217
    /**
218
     * @param ClassMetadata $metaData
219
     * @return string
220
     */
221
    private function buildBody(ClassMetadata $metaData): string
222
    {
223
        $fields = $this->buildFactoryData($metaData);
224
225
        $body = sprintf(
226
            "use League\\FactoryMuffin\\Faker\\Facade as Faker;
227
228
\$factory->_define(
229
    %s::class,
230
    [\n",
231
            $metaData->getName()
232
        );
233
234
        foreach ($fields as $field) {
235
            $body .= $field;
236
        }
237
238
        $body .= '
239
    ]
240
);';
241
        return $body;
242
    }
243
}