• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / schema-generator / 7104646209

05 Dec 2023 05:56PM UTC coverage: 79.191%. Remained the same
7104646209

push

github

dunglas
feat: allow symfony 7

1743 of 2201 relevant lines covered (79.19%)

16.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.81
/src/Command/GenerateCommand.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\SchemaGenerator\Command;
15

16
use ApiPlatform\SchemaGenerator\OpenApi\Generator as OpenApiGenerator;
17
use ApiPlatform\SchemaGenerator\Schema\Generator as SchemaGenerator;
18
use ApiPlatform\SchemaGenerator\SchemaGeneratorConfiguration;
19
use Symfony\Component\Config\Definition\Processor;
20
use Symfony\Component\Console\Command\Command;
21
use Symfony\Component\Console\Input\InputArgument;
22
use Symfony\Component\Console\Input\InputInterface;
23
use Symfony\Component\Console\Output\OutputInterface;
24
use Symfony\Component\Console\Question\ConfirmationQuestion;
25
use Symfony\Component\Console\Style\SymfonyStyle;
26
use Symfony\Component\Filesystem\Filesystem;
27
use Symfony\Component\Yaml\Parser;
28

29
/**
30
 * Generate entities command.
31
 *
32
 * @author Kévin Dunglas <dunglas@gmail.com>
33
 */
34
final class GenerateCommand extends Command
35
{
36
    private const DEFAULT_CONFIG_FILE = 'schema.yaml';
37

38
    private ?string $namespacePrefix = null;
39
    private ?string $defaultOutput = null;
40

41
    protected function configure(): void
42
    {
43
        $this->readComposer();
23✔
44

45
        $this
23✔
46
            ->setName('generate')
23✔
47
            ->setDescription('Generate the PHP code')
23✔
48
            ->addArgument('output', $this->defaultOutput ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The output directory', $this->defaultOutput)
23✔
49
            ->addArgument('config', InputArgument::OPTIONAL, 'The config file to use (default to "schema.yaml" in the current directory, will generate all types if no config file exists)');
23✔
50
    }
51

52
    private function readComposer(): void
53
    {
54
        if (file_exists('composer.json') && is_file('composer.json') && is_readable('composer.json')) {
23✔
55
            if (false === ($composerContent = file_get_contents('composer.json'))) {
23✔
56
                throw new \RuntimeException('Cannot read composer.json content.');
×
57
            }
58
            $composer = json_decode($composerContent, true, 512, \JSON_THROW_ON_ERROR);
23✔
59
            foreach ($composer['autoload']['psr-4'] ?? [] as $prefix => $output) {
23✔
60
                if ('' === $prefix) {
23✔
61
                    continue;
×
62
                }
63

64
                $this->namespacePrefix = $prefix;
23✔
65
                $this->defaultOutput = $output;
23✔
66

67
                break;
23✔
68
            }
69
        }
70
    }
71

72
    protected function execute(InputInterface $input, OutputInterface $output): int
73
    {
74
        $io = new SymfonyStyle($input, $output);
23✔
75

76
        $defaultOutput = $this->defaultOutput ? realpath($this->defaultOutput) : null;
23✔
77
        $outputDir = $input->getArgument('output');
23✔
78
        $configArgument = $input->getArgument('config');
23✔
79

80
        if ($dir = realpath($outputDir)) {
23✔
81
            if (!is_dir($dir)) {
22✔
82
                if (!$defaultOutput) {
×
83
                    throw new \InvalidArgumentException(sprintf('The file "%s" is not a directory.', $dir));
×
84
                }
85

86
                $dir = $defaultOutput;
×
87
                $configArgument = $outputDir;
×
88
            }
89

90
            if (!is_writable($dir)) {
22✔
91
                throw new \InvalidArgumentException(sprintf('The "%s" directory is not writable.', $dir));
×
92
            }
93

94
            $outputDir = $dir;
22✔
95
        } else {
96
            (new Filesystem())->mkdir($outputDir);
1✔
97
            $outputDir = realpath($outputDir);
1✔
98
            if (!$outputDir) {
1✔
99
                throw new \InvalidArgumentException(sprintf('The "%s" directory cannot be created.', $outputDir));
×
100
            }
101
        }
102

103
        if ($configArgument) {
23✔
104
            if (!file_exists($configArgument)) {
21✔
105
                throw new \InvalidArgumentException(sprintf('The file "%s" doesn\'t exist.', $configArgument));
×
106
            }
107

108
            if (!is_file($configArgument)) {
21✔
109
                throw new \InvalidArgumentException(sprintf('"%s" isn\'t a file.', $configArgument));
×
110
            }
111

112
            if (!is_readable($configArgument)) {
21✔
113
                throw new \InvalidArgumentException(sprintf('The file "%s" isn\'t readable.', $configArgument));
×
114
            }
115

116
            if (false === ($configContent = file_get_contents($configArgument))) {
21✔
117
                throw new \RuntimeException(sprintf('Cannot read "%s" content.', $configArgument));
×
118
            }
119
        } elseif (is_readable(self::DEFAULT_CONFIG_FILE)) {
2✔
120
            if (false === ($configContent = file_get_contents(self::DEFAULT_CONFIG_FILE))) {
1✔
121
                throw new \RuntimeException(sprintf('Cannot read "%s" content.', self::DEFAULT_CONFIG_FILE));
×
122
            }
123
        } else {
124
            if (!$io->askQuestion(new ConfirmationQuestion('Your project has no config file. The entire vocabulary will be imported.'.\PHP_EOL.'Continue?', false))) {
1✔
125
                return Command::SUCCESS;
1✔
126
            }
127
            $configContent = 'allTypes: true';
×
128
        }
129

130
        $configuration = $this->processConfiguration($configContent, $outputDir, $dir === $defaultOutput ? $this->namespacePrefix : null);
22✔
131

132
        (new SchemaGenerator())->generate($configuration, $output, $io);
22✔
133
        (new OpenApiGenerator())->generate($configuration, $configArgument ?? self::DEFAULT_CONFIG_FILE, $output, $io);
22✔
134

135
        return Command::SUCCESS;
22✔
136
    }
137

138
    /**
139
     * @return Configuration
140
     */
141
    private function processConfiguration(string $configContent, string $outputDir, ?string $defaultNamespacePrefix): array
142
    {
143
        $parser = new Parser();
22✔
144
        $config = $parser->parse($configContent);
22✔
145
        unset($parser);
22✔
146

147
        $processor = new Processor();
22✔
148
        $configuration = new SchemaGeneratorConfiguration($defaultNamespacePrefix);
22✔
149
        /** @var Configuration $processedConfiguration */
150
        $processedConfiguration = $processor->processConfiguration($configuration, [$config]);
22✔
151
        $processedConfiguration['output'] = $outputDir;
22✔
152
        if (!$processedConfiguration['output']) {
22✔
153
            throw new \RuntimeException('The specified output is invalid.');
×
154
        }
155

156
        return $processedConfiguration;
22✔
157
    }
158
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc