RelationsRenderer   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 91
c 0
b 0
f 0
dl 0
loc 138
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A renderKeys() 0 14 3
C render() 0 100 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Renderer\ConsoleRenderer\Renderer;
6
7
use Cycle\ORM\Relation;
8
use Cycle\ORM\SchemaInterface;
9
use Cycle\Schema\Renderer\ConsoleRenderer\Formatter;
10
use Cycle\Schema\Renderer\ConsoleRenderer\Renderer;
11
12
class RelationsRenderer implements Renderer
13
{
14
    private const STR_RELATION = [
15
        Relation::EMBEDDED => 'has embedded',
16
        Relation::HAS_ONE => 'has one',
17
        Relation::HAS_MANY => 'has many',
18
        Relation::BELONGS_TO => 'belongs to',
19
        Relation::REFERS_TO => 'refers to',
20
        Relation::MANY_TO_MANY => 'many to many',
21
        Relation::BELONGS_TO_MORPHED => 'belongs to morphed',
22
        Relation::MORPHED_HAS_ONE => 'morphed has one',
23
        Relation::MORPHED_HAS_MANY => 'morphed has many',
24
    ];
25
26
    private const STR_PREFETCH_MODE = [
27
        Relation::LOAD_PROMISE => 'lazy',
28
        Relation::LOAD_EAGER => 'eager',
29
    ];
30
31
    public function render(Formatter $formatter, array $schema, string $role): ?string
32
    {
33
        $title = \sprintf('%s:', $formatter->title('Relations'));
34
        $relations = $schema[SchemaInterface::RELATIONS] ?? [];
35
36
        if (\count($relations) === 0) {
37
            return $title . ' ' . $formatter->error('not defined');
38
        }
39
40
        $rows = [$title];
41
42
        foreach ($relations as $field => $relation) {
43
            $type = self::STR_RELATION[$relation[Relation::TYPE] ?? ''] ?? '?';
44
            $target = $relation[Relation::TARGET] ?? '?';
45
            $loading = self::STR_PREFETCH_MODE[$relation[Relation::LOAD] ?? ''] ?? 'default';
46
            $relSchema = $relation[Relation::SCHEMA];
47
            $innerKey = $relSchema[Relation::INNER_KEY] ?? '?';
48
            $outerKey = $relSchema[Relation::OUTER_KEY] ?? '?';
49
            $where = $relSchema[Relation::WHERE] ?? [];
50
            $cascade = $relSchema[Relation::CASCADE] ?? null;
51
            $cascadeStr = $cascade ? 'cascaded' : 'not cascaded';
52
            $nullable = $relSchema[Relation::NULLABLE] ?? null;
53
            $nullableStr = $nullable ? 'nullable' : ($nullable === false ? 'not null' : 'n/a');
54
            $morphKey = $relSchema[Relation::MORPH_KEY] ?? null;
55
56
            // Many-To-Many relation(s) options
57
            $mmInnerKey = $relSchema[Relation::THROUGH_INNER_KEY] ?? '?';
58
            $mmOuterKey = $relSchema[Relation::THROUGH_OUTER_KEY] ?? '?';
59
            $mmEntity = $relSchema[Relation::THROUGH_ENTITY] ?? null;
60
            $mmWhere = $relSchema[Relation::THROUGH_WHERE] ?? [];
61
62
            // print
63
            $row = \sprintf(
64
                '     %s->%s %s %s',
65
                $formatter->entity($role),
66
                $formatter->property($field),
67
                $type,
68
                $formatter->entity($target)
69
            );
70
71
            if ($morphKey !== null) {
72
                $row .= \sprintf(
73
                    ', %s: %s',
74
                    $formatter->title('morphed key'),
75
                    $this->renderKeys($formatter, $morphKey)
76
                );
77
            }
78
79
            $rows[] = $row . \sprintf(', %s loading, %s', $formatter->info($loading), $formatter->info($cascadeStr));
80
81
            $row = \sprintf(
82
                '       %s %s.%s <=',
83
                $nullableStr,
84
                $formatter->entity($role),
85
                $this->renderKeys($formatter, $innerKey)
86
            );
87
88
            if ($mmEntity !== null) {
89
                $row .= \sprintf(
90
                    ' %s.%s | %s.%s ',
91
                    $formatter->entity($mmEntity),
92
                    $this->renderKeys($formatter, $mmInnerKey),
93
                    $formatter->entity($mmEntity),
94
                    $this->renderKeys($formatter, $mmOuterKey)
95
                );
96
            }
97
98
            // todo: composite $outerKey
99
            $rows[] = $row . \sprintf(
100
                '=> %s.%s',
101
                $formatter->entity($target),
102
                $this->renderKeys($formatter, $outerKey)
103
            );
104
105
            if (count($where)) {
106
                $rows[] = \sprintf(
107
                    '%s: %s',
108
                    $formatter->title('Where'),
109
                    \str_replace(
110
                        ["\r\n", "\n"],
111
                        $formatter::LINE_SEPARATOR . '       ',
112
                        $formatter::LINE_SEPARATOR . print_r($where, true)
0 ignored issues
show
Bug introduced by
Are you sure print_r($where, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

112
                        $formatter::LINE_SEPARATOR . /** @scrutinizer ignore-type */ print_r($where, true)
Loading history...
113
                    )
114
                );
115
            }
116
117
            if (count($mmWhere)) {
118
                $rows[] = \sprintf(
119
                    '%s: %s',
120
                    $formatter->title('Through where'),
121
                    \str_replace(
122
                        ["\r\n", "\n"],
123
                        $formatter::LINE_SEPARATOR . '       ',
124
                        $formatter::LINE_SEPARATOR . print_r($mmWhere, true)
0 ignored issues
show
Bug introduced by
Are you sure print_r($mmWhere, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

124
                        $formatter::LINE_SEPARATOR . /** @scrutinizer ignore-type */ print_r($mmWhere, true)
Loading history...
125
                    )
126
                );
127
            }
128
        }
129
130
        return \implode($formatter::LINE_SEPARATOR, $rows);
131
    }
132
133
    /**
134
     * @param  array<string>|string  $keys
135
     */
136
    private function renderKeys(Formatter $formatter, $keys): string
137
    {
138
        $keys = (array)$keys;
139
        $braces = \count($keys) > 1;
140
        $keys = \array_map(
141
            static fn (string $key) => $formatter->property($key),
142
            $keys
143
        );
144
145
        return \sprintf(
146
            '%s%s%s',
147
            $braces ? '[' : '',
148
            \implode(', ', $keys),
149
            $braces ? ']' : ''
150
        );
151
    }
152
}
153