Passed
Pull Request — 2.x (#462)
by Aleksei
18:57
created

Insert::execute()   F

Complexity

Conditions 18
Paths 240

Size

Total Lines 77
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 18.4442

Importance

Changes 0
Metric Value
cc 18
eloc 43
c 0
b 0
f 0
nc 240
nop 0
dl 0
loc 77
ccs 16
cts 18
cp 0.8889
crap 18.4442
rs 3.5333

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\ORM\Command\Database;
6
7
use Cycle\Database\DatabaseInterface;
8
use Cycle\Database\Query\ReturningInterface;
9
use Cycle\ORM\Command\StoreCommand;
10
use Cycle\ORM\Command\Traits\ErrorTrait;
11
use Cycle\ORM\Command\Traits\MapperTrait;
12
use Cycle\ORM\Heap\State;
13
use Cycle\ORM\MapperInterface;
14
use Cycle\ORM\Schema\GeneratedField;
15
16
/**
17
 * Insert data into associated table and provide lastInsertID promise.
18
 */
19
final class Insert extends StoreCommand
20
{
21
    use ErrorTrait;
0 ignored issues
show
introduced by
The trait Cycle\ORM\Command\Traits\ErrorTrait requires some properties which are not provided by Cycle\ORM\Command\Database\Insert: $waitScope, $waitContext
Loading history...
22
    use MapperTrait;
23 1710
24
    /**
25
     * @param non-empty-string $table
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
26
     * @param string[] $primaryKeys
27
     * @param non-empty-string|null $pkColumn
28
     * @param array<non-empty-string, int> $generated
29
     */
30
    public function __construct(
31
        DatabaseInterface $db,
32 1710
        string $table,
33 1710
        State $state,
34
        ?MapperInterface $mapper,
35
        private array $primaryKeys = [],
36 2
        private ?string $pkColumn = null,
37
        private array $generated = [],
38 2
    ) {
39
        parent::__construct($db, $table, $state);
40
        $this->mapper = $mapper;
41 1700
    }
42
43 1700
    public function isReady(): bool
44
    {
45
        return true;
46
    }
47
48
    public function hasData(): bool
49
    {
50
        return match (true) {
51
            $this->columns !== [],
52
            $this->state->getData() !== [],
53
            $this->hasGeneratedFields() => true,
54
            default => false,
55
        };
56
    }
57
58
    public function getStoreData(): array
59 1698
    {
60
        if ($this->appendix !== []) {
61 1698
            $this->state->setData($this->appendix);
62
            $this->appendix = [];
63 1698
        }
64 56
        $data = $this->state->getData();
65
        return array_merge($this->columns, $this->mapper?->mapColumns($data) ?? $data);
66
    }
67 1698
68
    /**
69
     * Insert data into associated table.
70 1698
     */
71 1698
    public function execute(): void
72 1402
    {
73
        $state = $this->state;
74
        $returningFields = [];
75 1698
76
        if ($this->appendix !== []) {
77 1698
            $state->setData($this->appendix);
78 1698
        }
79 1698
80
        $uncasted = $data = $state->getData();
81 1698
82 370
        // filter PK null values
83
        foreach ($this->primaryKeys as $key) {
84
            if (!isset($uncasted[$key])) {
85 1698
                unset($uncasted[$key]);
86
            }
87 1682
        }
88 1466
        // unset db-generated fields if they are null
89 1466
        foreach ($this->generated as $column => $mode) {
90 1386
            if (($mode & GeneratedField::DB_INSERT) === 0x0) {
91
                continue;
92 1386
            }
93
94
            $returningFields[$column] = $mode;
95
            if (!isset($uncasted[$column])) {
96
                unset($uncasted[$column]);
97 1682
            }
98
        }
99 1682
        $uncasted = $this->prepareData($uncasted);
100
101
        $insert = $this->db
102
            ->insert($this->table)
0 ignored issues
show
Bug introduced by
It seems like $this->table can also be of type null; however, parameter $table of Cycle\Database\DatabaseInterface::insert() 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

102
            ->insert(/** @scrutinizer ignore-type */ $this->table)
Loading history...
103
            ->values(\array_merge($this->columns, $uncasted));
104
105
        if ($this->pkColumn !== null && $returningFields === []) {
106
            $returningFields[$this->primaryKeys[0]] ??= $this->pkColumn;
107
        }
108
109
        if ($insert instanceof ReturningInterface && $returningFields !== []) {
110
            // Map generated fields to columns
111
            $returning = $this->mapper->mapColumns($returningFields);
0 ignored issues
show
Bug introduced by
The method mapColumns() does not exist on null. ( Ignorable by Annotation )

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

111
            /** @scrutinizer ignore-call */ 
112
            $returning = $this->mapper->mapColumns($returningFields);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
112
            // Array of [field name => column name]
113
            $returning = \array_combine(\array_keys($returningFields), \array_keys($returning));
114
115
            $insert->returning(...\array_values($returning));
116
117
            $insertID = $insert->run();
118
119
            if (\count($returning) === 1) {
120
                $field = \array_key_first($returning);
121
                $state->register(
122
                    $field,
123
                    $this->mapper === null ? $insertID : $this->mapper->cast([$field => $insertID])[$field],
124
                );
125
            } else {
126
                foreach ($this->mapper->cast($insertID) as $field => $value) {
127
                    $state->register($field, $value);
128
                }
129
            }
130
        } else {
131
            $insertID = $insert->run();
132
133
            if ($insertID !== null && \count($this->primaryKeys) === 1) {
134
                $fpk = $this->primaryKeys[0]; // first PK
135
                if (!isset($data[$fpk])) {
136
                    $state->register(
137
                        $fpk,
138
                        $this->mapper === null ? $insertID : $this->mapper->cast([$fpk => $insertID])[$fpk]
139
                    );
140
                }
141
            }
142
        }
143
144
145
        $state->updateTransactionData();
146
147
        parent::execute();
148
    }
149
150
    public function register(string $key, mixed $value): void
151
    {
152
        $this->state->register($key, $value);
153
    }
154
155
    /**
156
     * Has fields that weren't provided but will be generated by the database or PHP.
157
     */
158
    private function hasGeneratedFields(): bool
159
    {
160
        if ($this->generated === []) {
161
            return false;
162
        }
163
164
        $data = $this->state->getData();
165
166
        foreach ($this->generated as $field => $mode) {
167
            if (($mode & (GeneratedField::DB_INSERT | GeneratedField::PHP_INSERT)) === 0x0) {
168
                continue;
169
            }
170
171
            if (!isset($data[$field])) {
172
                return true;
173
            }
174
        }
175
176
        return true;
177
    }
178
}
179