Passed
Push — master ( 10daf0...4112ec )
by
unknown
01:30
created

SchemaCommand::execute()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 7
c 1
b 0
f 0
nc 12
nop 2
dl 0
loc 12
ccs 0
cts 10
cp 0
crap 30
rs 9.6111
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Cycle\Command\Common;
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\CycleDependencyPromise;
16
17
final class SchemaCommand extends Command
18
{
19
    protected static $defaultName = 'cycle/schema';
20
21
    private CycleDependencyPromise $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(CycleDependencyPromise $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
        $roleArgument = $input->getArgument('role');
52
        $result = true;
53
        $schema = $this->promise->getSchema();
54
        $roles = $roleArgument !== null ? explode(',', $roleArgument) : $schema->getRoles();
0 ignored issues
show
Bug introduced by
It seems like $roleArgument can also be of type string[]; however, parameter $string of explode() 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

54
        $roles = $roleArgument !== null ? explode(',', /** @scrutinizer ignore-type */ $roleArgument) : $schema->getRoles();
Loading history...
55
56
        foreach ($roles as $role) {
57
            $result = $this->displaySchema($schema, $role, $output) && $result;
58
        }
59
60
        return $result ? ExitCode::OK : ExitCode::UNSPECIFIED_ERROR;
61
    }
62
63
    /**
64
     * Write a role schema in the output
65
     *
66
     * @param SchemaInterface $schema Data schema
67
     * @param string $role Role to display
68
     * @param OutputInterface $output Output console
69
     * @return void
70
     */
71
    private function displaySchema(SchemaInterface $schema, string $role, OutputInterface $output): bool
72
    {
73
        if (!$schema->defines($role)) {
74
            $output->writeln("<fg=red>Role</> <fg=magenta>[{$role}]</> <fg=red>not defined!</>");
75
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type void.
Loading history...
76
        }
77
78
        $output->write("<fg=magenta>[{$role}</>");
79
        $alias = $schema->resolveAlias($role);
80
        // alias
81
        if ($alias !== null && $alias !== $role) {
82
            $output->write("=><fg=magenta>{$alias}</>");
83
        }
84
        $output->write("<fg=magenta>]</>");
85
86
        // database and table
87
        $database = $schema->define($role, Schema::DATABASE);
88
        $table = $schema->define($role, Schema::TABLE);
89
        if ($database !== null) {
90
            $output->write(" :: <fg=green>{$database}</>.<fg=green>{$table}</>");
91
        }
92
        $output->writeln('');
93
94
        // Entity
95
        $entity = $schema->define($role, Schema::ENTITY);
96
        $output->write('   Entity     : ');
97
        $output->writeln($entity === null ? 'no entity' : "<fg=blue>{$entity}</>");
98
        // Mapper
99
        $mapper = $schema->define($role, Schema::MAPPER);
100
        $output->write('   Mapper     : ');
101
        $output->writeln($mapper === null ? 'no mapper' : "<fg=blue>{$mapper}</>");
102
        // Constrain
103
        $constrain = $schema->define($role, Schema::CONSTRAIN);
104
        $output->write('   Constrain  : ');
105
        $output->writeln($constrain === null ? 'no constrain' : "<fg=blue>{$constrain}</>");
106
        // Repository
107
        $repository = $schema->define($role, Schema::REPOSITORY);
108
        $output->write('   Repository : ');
109
        $output->writeln($repository === null ? 'no repository' : "<fg=blue>{$repository}</>");
110
        // PK
111
        $pk = $schema->define($role, Schema::PRIMARY_KEY);
112
        $output->write('   Primary key: ');
113
        $output->writeln($pk === null ? 'no primary key' : "<fg=green>{$pk}</>");
114
        // Fields
115
        $columns = $schema->define($role, Schema::COLUMNS);
116
        $output->writeln("   Fields     :");
117
        $output->writeln("     (<fg=cyan>property</> -> <fg=green>db.field</> -> <fg=blue>typecast</>)");
118
        $types = $schema->define($role, Schema::TYPECAST);
119
        foreach ($columns as $property => $field) {
120
            $typecast = $types[$property] ?? $types[$field] ?? null;
121
            $output->write("     <fg=cyan>{$property}</> -> <fg=green>{$field}</>");
122
            if ($typecast !== null) {
123
                $output->write(" -> <fg=blue>{$typecast}</>");
124
            }
125
            $output->writeln('');
126
        }
127
128
        // Relations
129
        $relations = $schema->define($role, Schema::RELATIONS);
130
        if (count($relations) > 0) {
131
            $output->writeln('   Relations  :');
132
            foreach ($relations as $field => $relation) {
133
                $type = self::STR_RELATION[$relation[Relation::TYPE] ?? ''] ?? '?';
134
                $target = $relation[Relation::TARGET] ?? '?';
135
                $loading = self::STR_PREFETCH_MODE[$relation[Relation::LOAD] ?? ''] ?? '?';
136
                $relSchema = $relation[Relation::SCHEMA];
137
                $innerKey = $relSchema[Relation::INNER_KEY] ?? '?';
138
                $outerKey = $relSchema[Relation::OUTER_KEY] ?? '?';
139
                $where = $relSchema[Relation::WHERE] ?? [];
140
                $cascade = $relSchema[Relation::CASCADE] ?? null;
141
                $cascadeStr = $cascade ? 'cascaded' : 'not cascaded';
142
                $nullable = $relSchema[Relation::NULLABLE] ?? null;
143
                $nullableStr = $nullable ? 'nullable' : ($nullable === false ? 'not null' : 'n/a');
144
                $morphKey = $relSchema[Relation::MORPH_KEY] ?? null;
145
                // Many-To-Many relation(s) options
146
                $mmInnerKey = $relSchema[Relation::THROUGH_INNER_KEY] ?? '?';
147
                $mmOuterKey = $relSchema[Relation::THROUGH_OUTER_KEY] ?? '?';
148
                $mmEntity = $relSchema[Relation::THROUGH_ENTITY] ?? null;
149
                $mmWhere = $relSchema[Relation::THROUGH_WHERE] ?? [];
150
                // print
151
                $output->write(
152
                    "     <fg=magenta>{$role}</>-><fg=cyan>{$field}</> "
153
                    . "{$type} <fg=magenta>{$target}</> {$loading} load"
154
                );
155
                if ($morphKey !== null) {
156
                    $output->writeln("       Morphed key: <fg=green>{$morphKey}</>");
157
                }
158
                $output->writeln(" <fg=yellow>{$cascadeStr}</>");
159
                $output->write("       {$nullableStr} <fg=green>{$table}</>.<fg=green>{$innerKey}</> <=");
160
                if ($mmEntity !== null) {
161
                    $output->write(" <fg=magenta>{$mmEntity}</>.<fg=green>{$mmInnerKey}</>");
162
                    $output->write("|");
163
                    $output->write("<fg=magenta>{$mmEntity}</>.<fg=green>{$mmOuterKey}</> ");
164
                }
165
                $output->writeln("=> <fg=magenta>{$target}</>.<fg=green>{$outerKey}</> ");
166
                if (count($where)) {
167
                    $output->write("       Where:");
168
                    $output->writeln(str_replace(["\r\n", "\n"], "\n       ", "\n" . print_r($where, 1)));
169
                }
170
                if (count($mmWhere)) {
171
                    $output->write("       Through where:");
172
                    $output->writeln(str_replace(["\r\n", "\n"], "\n       ", "\n" . print_r($mmWhere, 1)));
173
                }
174
            }
175
        } else {
176
            $output->writeln('   No relations');
177
        }
178
        return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type void.
Loading history...
179
    }
180
}
181