Passed
Push — master ( 463a83...b762ea )
by Curtis
01:58
created

GenerateTraitCommand::execute()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 73
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 44
dl 0
loc 73
rs 9.216
c 0
b 0
f 0
cc 3
nc 3
nop 2

How to fix   Long Method   

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
 * @noinspection PhpUndefinedFieldInspection
4
 */
5
6
namespace DoctrineRepoHelper\Command;
7
8
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
9
use Doctrine\ORM\EntityManager;
10
use Doctrine\ORM\EntityRepository;
11
use Symfony\Component\Console\Command\Command;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Input\InputOption;
14
use Symfony\Component\Console\Output\OutputInterface;
15
use Zend\Code\Generator\DocBlockGenerator;
16
use Zend\Code\Generator\Exception\InvalidArgumentException;
17
use Zend\Code\Generator\FileGenerator;
18
use Zend\Code\Generator\MethodGenerator;
19
use Zend\Code\Generator\TraitGenerator;
20
21
/**
22
 * Class GenerateTraitCommand
23
 * @package DoctrineRepoHelper\Command
24
 */
25
class GenerateTraitCommand extends Command
26
{
27
    /** @var EntityManager */
28
    protected $entityManager;
29
30
    /**
31
     * GenerateTraitCommand constructor.
32
     * @param EntityManager $entityManager
33
     */
34
    public function __construct(EntityManager $entityManager)
35
    {
36
        $this->entityManager = $entityManager;
37
        parent::__construct();
38
    }
39
40
    protected function configure()
41
    {
42
        parent::configure();
43
44
        $this
45
            ->setName('orm:generate-repository-trait')
46
            ->setDescription('Generate a repository helper trait')
47
            ->setHelp(
48
                <<<EOT
49
The generate repository trait command creates a trait that will allow your development environment to autocomplete
50
custom repository methods
51
EOT
52
            )
53
            ->addOption(
54
                'namespace',
55
                null,
56
                InputOption::VALUE_OPTIONAL,
57
                'Declares the namespace'
58
            )
59
            ->addOption(
60
                'destination',
61
                null,
62
                InputOption::VALUE_OPTIONAL,
63
                'Path to create the trait in',
64
                getcwd()
65
            )
66
            ->addOption(
67
                'classname',
68
                null,
69
                InputOption::VALUE_OPTIONAL,
70
                'Classname of the trait',
71
                'CustomRepositoryAwareTrait'
72
            )
73
            ->addOption(
74
                'em-getter',
75
                null,
76
                InputOption::VALUE_OPTIONAL,
77
                'Name of the property or method classes that use the trait will have to access the EntityManager',
78
                'getObjectManager()'
79
            );
80
    }
81
82
    /**
83
     * @param InputInterface $input
84
     * @param OutputInterface $output
85
     * @return int|void|null
86
     * @throws \ReflectionException
87
     */
88
    public function execute(InputInterface $input, OutputInterface $output)
89
    {
90
        $traitName = $input->getOption('classname');
91
        $outputFileName = sprintf(
92
            '%s/%s.php',
93
            $input->getOption('destination'),
0 ignored issues
show
Bug introduced by
It seems like $input->getOption('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

93
            /** @scrutinizer ignore-type */ $input->getOption('destination'),
Loading history...
94
            $traitName
95
        );
96
97
        $metaDataEntries = $this->entityManager->getMetadataFactory()->getAllMetadata();
98
        $trait = $this->generateTrait(
99
            $input,
100
            $output
101
        );
102
103
        foreach ($metaDataEntries as $metaData) {
104
            $method = $this->generateMethod(
105
                $input,
106
                $output,
107
                $metaData
108
            );
109
110
            try {
111
                $trait->addMethodFromGenerator($method);
112
113
            } catch (InvalidArgumentException $e) {
114
                $output->writeln(
115
                    sprintf(
116
                        'Method "%s" already exists in this class',
117
                        $method->getName()
118
                    )
119
                );
120
121
                $reflection = new \ReflectionClass($metaData->getName());
122
123
                $method->setName(
124
                    sprintf(
125
                        'get%sRepository%s',
126
                        $reflection->getShortName(),
127
                        str_replace('.', '', uniqid('', true))
128
                    )
129
                );
130
131
                $trait->addMethodFromGenerator($method);
132
133
                $output->writeln(
134
                    sprintf(
135
                        'Refactored the method to "%s". Please refactor to a usable name you will remember',
136
                        $method->getName()
137
                    )
138
                );
139
                $output->writeln('');
140
            }
141
        }
142
143
        $file = new FileGenerator();
144
        $file->setClass($trait);
145
146
        file_put_contents(
147
            $outputFileName,
148
            $file->generate()
149
        );
150
151
        $output->writeln('');
152
153
        $output->writeln(
154
            sprintf(
155
                'Trait created in "%s"',
156
                $outputFileName
157
            )
158
        );
159
160
        $output->writeln('');
161
    }
162
163
    /**
164
     * @param InputInterface $input
165
     * @param OutputInterface $output
166
     * @return TraitGenerator
167
     */
168
    private function generateTrait(InputInterface $input, OutputInterface $output): TraitGenerator
0 ignored issues
show
Unused Code introduced by
The parameter $output is not used and could be removed. ( Ignorable by Annotation )

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

168
    private function generateTrait(InputInterface $input, /** @scrutinizer ignore-unused */ OutputInterface $output): TraitGenerator

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
169
    {
170
        $entityManagerGetter = $input->getOption('em-getter');
171
        $traitName = $input->getOption('classname');
172
        $traitNameSpace = $input->getOption('namespace');
173
174
        $trait = new TraitGenerator(
175
            $traitName,
0 ignored issues
show
Bug introduced by
It seems like $traitName can also be of type string[]; however, parameter $name of Zend\Code\Generator\TraitGenerator::__construct() 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

175
            /** @scrutinizer ignore-type */ $traitName,
Loading history...
176
            $traitNameSpace
0 ignored issues
show
Bug introduced by
It seems like $traitNameSpace can also be of type string[]; however, parameter $namespaceName of Zend\Code\Generator\TraitGenerator::__construct() 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

176
            /** @scrutinizer ignore-type */ $traitNameSpace
Loading history...
177
        );
178
179
        $trait
180
            ->addUse(EntityManager::class)
181
            ->addUse(EntityRepository::class);
182
183
        $docBlock = DocBlockGenerator::fromArray(
184
            [
185
                'shortDescription' => $traitName,
186
                'longDescription' => 'Provides helper methods for accessing custom repositories. Provides type hints to allow for custom method auto-completion within IDEs',
187
                'tags' => [
188
                    [
189
                        'name' => 'package',
190
                        'description' => $traitNameSpace
191
                    ],
192
                    [
193
                        'name' => 'method',
194
                        'description' => sprintf(
195
                            'EntityManager %s',
196
                            $entityManagerGetter
0 ignored issues
show
Bug introduced by
It seems like $entityManagerGetter 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

196
                            /** @scrutinizer ignore-type */ $entityManagerGetter
Loading history...
197
                        )
198
                    ]
199
                ]
200
            ]
201
        );
202
203
        $trait->setDocBlock($docBlock);
204
        return $trait;
205
    }
206
207
    /**
208
     * @param ClassMetadata $metaData
209
     * @param InputInterface $input
210
     * @param OutputInterface $output
211
     * @return MethodGenerator
212
     * @throws \ReflectionException
213
     */
214
    private function generateMethod(InputInterface $input, OutputInterface $output, ClassMetadata $metaData): MethodGenerator
0 ignored issues
show
Unused Code introduced by
The parameter $output is not used and could be removed. ( Ignorable by Annotation )

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

214
    private function generateMethod(InputInterface $input, /** @scrutinizer ignore-unused */ OutputInterface $output, ClassMetadata $metaData): MethodGenerator

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
215
    {
216
        $entityManagerGetter = $input->getOption('em-getter');
217
218
        $reflection = new \ReflectionClass($metaData->getName());
219
        $repoReflection = null;
220
221
        if ($metaData->customRepositoryClassName) {
0 ignored issues
show
Bug introduced by
Accessing customRepositoryClassName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
222
            $repoReflection = new \ReflectionClass($metaData->customRepositoryClassName);
223
        }
224
225
        $method = new MethodGenerator(
226
            sprintf(
227
                'get%sRepository',
228
                $reflection->getShortName()
229
            ),
230
            [],
231
            MethodGenerator::FLAG_PUBLIC,
232
            sprintf(
233
                'return $this->%s->getRepository(\\%s::class);',
234
                $entityManagerGetter,
0 ignored issues
show
Bug introduced by
It seems like $entityManagerGetter 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

234
                /** @scrutinizer ignore-type */ $entityManagerGetter,
Loading history...
235
                $reflection->getName()
236
            )
237
        );
238
239
240
        $docBlock = DocBlockGenerator::fromArray(
241
            [
242
                'tags' => [
243
                    [
244
                        'name' => 'return',
245
                        'description' => sprintf(
246
                            '%s%s',
247
                            'EntityRepository',
248
                            $repoReflection ? '|\\' . $repoReflection->getName() : ''
249
                        )
250
                    ]
251
                ]
252
            ]
253
        );
254
255
        $method->setDocBlock($docBlock);
256
        return $method;
257
    }
258
}