Passed
Pull Request — 2.1 (#66)
by Vincent
22:57 queued 15:10
created

CriteriaCommand::execute()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
c 1
b 0
f 0
dl 0
loc 25
ccs 15
cts 15
cp 1
rs 9.7998
cc 3
nc 3
nop 2
crap 3
1
<?php
2
3
namespace Bdf\Prime\Console;
4
5
use Bdf\Prime\Entity\CriteriaGenerator;
6
use Bdf\Prime\Mapper\Mapper;
7
use Bdf\Prime\ServiceLocator;
8
use Bdf\Util\Console\BdfStyle;
9
use Bdf\Util\File\ClassFileLocator;
10
use Bdf\Util\File\PhpClassFile;
11
use Symfony\Component\Console\Attribute\AsCommand;
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Input\InputArgument;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Filesystem\Filesystem;
18
19
use function file_exists;
20
use function is_dir;
21
use function realpath;
22
use function str_replace;
23
use function str_starts_with;
24
25
/**
26
 * Command for generate a custom criteria class from a mapper
27
 */
28
#[AsCommand('prime:criteria', 'Generate criteria class by mapper')]
29
class CriteriaCommand extends Command
30
{
31
    public const CLASS_SUFFIX = 'Criteria';
32
33
    protected static $defaultName = 'prime:criteria';
34
35
    private ServiceLocator $locator;
36
37
    /**
38
     * EntityCommand constructor.
39
     *
40
     * @param ServiceLocator $locator
41
     */
42 8
    public function __construct(ServiceLocator $locator)
43
    {
44 8
        parent::__construct(static::$defaultName);
45
46 8
        $this->locator = $locator;
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52 8
    protected function configure(): void
53
    {
54 8
        $this
55 8
            ->addArgument('mapper', InputArgument::REQUIRED, 'Mapper file or directory to parse')
56 8
            ->addOption('backup', 'b', InputOption::VALUE_NONE, 'Backup file if exists')
57 8
            ->addOption('show', 's', InputOption::VALUE_NONE, 'Show generated code')
58 8
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not write generated code')
59 8
            ->setDescription('Generate criteria class by mapper')
60 8
            ->setHelp(
61 8
                <<<EOF
62
The <info>%command.name%</info> generate criteria from mapper
63
use mapper argument to parse a directory or a mapper file
64
  <info>php %command.full_name% app/models</info>
65
  <info>php %command.full_name% app/models/MyMapper.php</info>
66
67
Backup files with backup option
68
  <info>php %command.full_name% --backup app/models</info>
69
  <info>php %command.full_name% -b app/models</info>
70
71
To only show generated code, use show option in combination with dry-run
72
  <info>php %command.full_name% --show --dry-run app/models</info>
73
74 8
EOF
75 8
            )
76 8
        ;
77
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82 8
    protected function execute(InputInterface $input, OutputInterface $output): int
83
    {
84 8
        $io = new BdfStyle($input, $output);
85
86 8
        $path = realpath($io->argument('mapper'));
87
88 8
        $cache = $this->locator->mappers()->getMetadataCache();
89 8
        $this->locator->mappers()->setMetadataCache(null);
90
91 8
        foreach ($this->getClassIterator($path) as $classInfo) {
92 8
            $className = $classInfo->getClass();
93
94 8
            if (!$this->locator->mappers()->isMapper($className)) {
95 6
                $io->debug("'{$className}' is not mapper class");
96 6
                continue;
97
            }
98
99 7
            $mapper = $this->locator->mappers()->createMapper($this->locator, $className);
100 7
            $generator = new CriteriaGenerator($mapper->getEntityClass() . self::CLASS_SUFFIX);
101
102 7
            $this->runUserActions($io, $generator, $mapper, $classInfo);
0 ignored issues
show
Bug introduced by
It seems like $mapper can also be of type null; however, parameter $mapper of Bdf\Prime\Console\Criter...mmand::runUserActions() does only seem to accept Bdf\Prime\Mapper\Mapper, 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

102
            $this->runUserActions($io, $generator, /** @scrutinizer ignore-type */ $mapper, $classInfo);
Loading history...
103
        }
104
105 8
        $this->locator->mappers()->setMetadataCache($cache);
106 8
        return 0;
107
    }
108
109
    /**
110
     * @param string $path
111
     *
112
     * @return iterable<PhpClassFile>
113
     */
114 8
    protected function getClassIterator(string $path): iterable
115
    {
116 8
        if (is_dir($path)) {
117 6
            return new ClassFileLocator($path);
118
        } else {
119 2
            $classFile = new PhpClassFile($path);
120 2
            $classFile->extractClassInfo();
121
122 2
            return [$classFile];
123
        }
124
    }
125
126 7
    protected function runUserActions(BdfStyle $io, CriteriaGenerator $generator, Mapper $mapper, PhpClassFile $classInfo): void
127
    {
128 7
        $fileName = str_replace('Mapper', self::CLASS_SUFFIX, $classInfo->getRealPath());
129 7
        $filesystem = new Filesystem();
130
131 7
        if (file_exists($fileName)) {
132 4
            $userChoice = (string) $io->choice("'$fileName' exists. what do you want ?", [
133 4
                '1'     => 'Regenerate: will replace the existing entity',
134 4
                '2'     => 'Update: will complete entity with new properties and methods',
135 4
                '3'     => 'Cancel',
136 4
            ]);
137
138 4
            if ($userChoice === 'Cancel') {
139 1
                return;
140
            }
141
142 3
            if (str_starts_with($userChoice, 'Update')) {
143 2
                $generator->loadFromFile($fileName);
144
            }
145
146 3
            if ($io->option('backup') && !$io->option('dry-run')) {
147 1
                $filesystem->copy($fileName, $fileName.'.bak');
148 1
                $io->comment('backup file "' . $fileName.'.bak' . '"');
149
            }
150
        }
151
152 6
        $generator->parseMetadata($mapper->metadata());
153 6
        $generator->parseCustomFilters($mapper->filters());
154
155 6
        $code = $generator->dump();
156
157 6
        if ($io->option('show')) {
158 2
            $io->writeln($code);
159
        }
160
161 6
        if (!$io->option('dry-run')) {
162 4
            $filesystem->dumpFile($fileName, $code);
163 4
            $io->comment('generated file "' . $fileName . '"');
164
        }
165
    }
166
}
167