Passed
Push — master ( 57a6ca...7ee914 )
by Aleksei
02:24
created

SchemaCommand   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 28
eloc 105
dl 0
loc 164
ccs 0
cts 92
cp 0
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A execute() 0 13 5
A __construct() 0 4 1
D displaySchema() 0 108 21
A configure() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Cycle\Command\Schema;
6
7
use Cycle\ORM\Relation;
8
use Cycle\ORM\Schema;
9
use Cycle\ORM\SchemaInterface;
10
use Symfony\Component\Console\Command\Command;
11
use Symfony\Component\Console\Input\InputArgument;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Output\OutputInterface;
14
use Yiisoft\Yii\Console\ExitCode;
15
use Yiisoft\Yii\Cycle\Command\CycleDependencyProxy;
16
17
final class SchemaCommand extends Command
18
{
19
    protected static $defaultName = 'cycle/schema';
20
21
    private CycleDependencyProxy $promise;
22
    private const STR_RELATION = [
23
        Relation::HAS_ONE => 'has one',
24
        Relation::HAS_MANY => 'has many',
25
        Relation::BELONGS_TO => 'belongs to',
26
        Relation::REFERS_TO => 'refers to',
27
        Relation::MANY_TO_MANY => 'many to many',
28
        Relation::BELONGS_TO_MORPHED => 'belongs to morphed',
29
        Relation::MORPHED_HAS_ONE => 'morphed has one',
30
        Relation::MORPHED_HAS_MANY => 'morphed has many',
31
    ];
32
    private const STR_PREFETCH_MODE = [
33
        Relation::LOAD_PROMISE => 'promise',
34
        Relation::LOAD_EAGER => 'eager',
35
    ];
36
37
    public function __construct(CycleDependencyProxy $promise)
38
    {
39
        $this->promise = $promise;
40
        parent::__construct();
41
    }
42
43
    public function configure(): void
44
    {
45
        $this->setDescription('Shown current schema');
46
        $this->addArgument('role', InputArgument::OPTIONAL, 'Roles to display (separated by ",").');
47
    }
48
49
    protected function execute(InputInterface $input, OutputInterface $output): int
50
    {
51
        /** @var string|null $roleArgument */
52
        $roleArgument = $input->getArgument('role');
53
        $result = true;
54
        $schema = $this->promise->getSchema();
55
        $roles = $roleArgument !== null ? explode(',', $roleArgument) : $schema->getRoles();
56
57
        foreach ($roles as $role) {
58
            $result = $this->displaySchema($schema, $role, $output) && $result;
59
        }
60
61
        return $result ? ExitCode::OK : ExitCode::UNSPECIFIED_ERROR;
62
    }
63
64
    /**
65
     * Write a role schema in the output
66
     *
67
     * @param SchemaInterface $schema Data schema
68
     * @param string $role Role to display
69
     * @param OutputInterface $output Output console
70
     *
71
     * @return bool
72
     */
73
    private function displaySchema(SchemaInterface $schema, string $role, OutputInterface $output): bool
74
    {
75
        if (!$schema->defines($role)) {
76
            $output->writeln("<fg=red>Role</> <fg=magenta>[{$role}]</> <fg=red>not defined!</>");
77
            return false;
78
        }
79
80
        $output->write("<fg=magenta>[{$role}</>");
81
        $alias = $schema->resolveAlias($role);
82
        // alias
83
        if ($alias !== null && $alias !== $role) {
84
            $output->write("=><fg=magenta>{$alias}</>");
85
        }
86
        $output->write('<fg=magenta>]</>');
87
88
        // database and table
89
        $database = $schema->define($role, Schema::DATABASE);
90
        $table = $schema->define($role, Schema::TABLE);
91
        if ($database !== null) {
92
            $output->write(" :: <fg=green>{$database}</>.<fg=green>{$table}</>");
93
        }
94
        $output->writeln('');
95
96
        // Entity
97
        $entity = $schema->define($role, Schema::ENTITY);
98
        $output->write('   Entity     : ');
99
        $output->writeln($entity === null ? 'no entity' : "<fg=blue>{$entity}</>");
100
        // Mapper
101
        $mapper = $schema->define($role, Schema::MAPPER);
102
        $output->write('   Mapper     : ');
103
        $output->writeln($mapper === null ? 'no mapper' : "<fg=blue>{$mapper}</>");
104
        // Constrain
105
        $constrain = $schema->define($role, Schema::CONSTRAIN);
106
        $output->write('   Constrain  : ');
107
        $output->writeln($constrain === null ? 'no constrain' : "<fg=blue>{$constrain}</>");
108
        // Repository
109
        $repository = $schema->define($role, Schema::REPOSITORY);
110
        $output->write('   Repository : ');
111
        $output->writeln($repository === null ? 'no repository' : "<fg=blue>{$repository}</>");
112
        // PK
113
        $pk = $schema->define($role, Schema::PRIMARY_KEY);
114
        $output->write('   Primary key: ');
115
        $output->writeln($pk === null ? 'no primary key' : "<fg=green>{$pk}</>");
116
        // Fields
117
        $columns = $schema->define($role, Schema::COLUMNS);
118
        $output->writeln('   Fields     :');
119
        $output->writeln('     (<fg=cyan>property</> -> <fg=green>db.field</> -> <fg=blue>typecast</>)');
120
        $types = $schema->define($role, Schema::TYPECAST);
121
        foreach ($columns as $property => $field) {
122
            $typecast = $types[$property] ?? $types[$field] ?? null;
123
            $output->write("     <fg=cyan>{$property}</> -> <fg=green>{$field}</>");
124
            if ($typecast !== null) {
125
                $output->write(sprintf(' -> <fg=blue>%s</>', implode('::', (array)$typecast)));
126
            }
127
            $output->writeln('');
128
        }
129
130
        // Relations
131
        $relations = $schema->define($role, Schema::RELATIONS);
132
        if (count($relations) > 0) {
133
            $output->writeln('   Relations  :');
134
            foreach ($relations as $field => $relation) {
135
                $type = self::STR_RELATION[$relation[Relation::TYPE] ?? ''] ?? '?';
136
                $target = $relation[Relation::TARGET] ?? '?';
137
                $loading = self::STR_PREFETCH_MODE[$relation[Relation::LOAD] ?? ''] ?? '?';
138
                $relSchema = $relation[Relation::SCHEMA];
139
                $innerKey = $relSchema[Relation::INNER_KEY] ?? '?';
140
                $outerKey = $relSchema[Relation::OUTER_KEY] ?? '?';
141
                $where = $relSchema[Relation::WHERE] ?? [];
142
                $cascade = $relSchema[Relation::CASCADE] ?? null;
143
                $cascadeStr = $cascade ? 'cascaded' : 'not cascaded';
144
                $nullable = $relSchema[Relation::NULLABLE] ?? null;
145
                $nullableStr = $nullable ? 'nullable' : ($nullable === false ? 'not null' : 'n/a');
146
                $morphKey = $relSchema[Relation::MORPH_KEY] ?? null;
147
                // Many-To-Many relation(s) options
148
                $mmInnerKey = $relSchema[Relation::THROUGH_INNER_KEY] ?? '?';
149
                $mmOuterKey = $relSchema[Relation::THROUGH_OUTER_KEY] ?? '?';
150
                $mmEntity = $relSchema[Relation::THROUGH_ENTITY] ?? null;
151
                $mmWhere = $relSchema[Relation::THROUGH_WHERE] ?? [];
152
                // print
153
                $output->write(
154
                    "     <fg=magenta>{$role}</>-><fg=cyan>{$field}</> "
155
                    . "{$type} <fg=magenta>{$target}</> {$loading} load"
156
                );
157
                if ($morphKey !== null) {
158
                    $output->writeln("       Morphed key: <fg=green>{$morphKey}</>");
159
                }
160
                $output->writeln(" <fg=yellow>{$cascadeStr}</>");
161
                $output->write("       {$nullableStr} <fg=green>{$table}</>.<fg=green>{$innerKey}</> <=");
162
                if ($mmEntity !== null) {
163
                    $output->write(" <fg=magenta>{$mmEntity}</>.<fg=green>{$mmInnerKey}</>");
164
                    $output->write('|');
165
                    $output->write("<fg=magenta>{$mmEntity}</>.<fg=green>{$mmOuterKey}</> ");
166
                }
167
                $output->writeln("=> <fg=magenta>{$target}</>.<fg=green>{$outerKey}</> ");
168
                if (count($where)) {
169
                    $output->write('       Where:');
170
                    $output->writeln(str_replace(["\r\n", "\n"], "\n       ", "\n" . print_r($where, true)));
171
                }
172
                if (count($mmWhere)) {
173
                    $output->write('       Through where:');
174
                    $output->writeln(str_replace(["\r\n", "\n"], "\n       ", "\n" . print_r($mmWhere, true)));
175
                }
176
            }
177
        } else {
178
            $output->writeln('   No relations');
179
        }
180
        return true;
181
    }
182
}
183