Passed
Push — master ( c61f9e...7fd889 )
by Anton
02:31
created

Insert::execute()   B

Complexity

Conditions 7
Paths 14

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 14
nop 0
dl 0
loc 33
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Cycle DataMapper ORM
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\ORM\Command\Database;
13
14
use Cycle\ORM\Command\DatabaseCommand;
15
use Cycle\ORM\Command\InitCarrierInterface;
16
use Cycle\ORM\Command\Traits\ContextTrait;
17
use Cycle\ORM\Command\Traits\ErrorTrait;
18
use Cycle\ORM\Context\ConsumerInterface;
19
use Cycle\ORM\Context\ProducerInterface;
20
use Cycle\ORM\Exception\CommandException;
21
use Spiral\Database\DatabaseInterface;
22
use Spiral\Database\Driver\Postgres\Query\PostgresInsertQuery;
23
24
/**
25
 * Insert data into associated table and provide lastInsertID promise.
26
 */
27
final class Insert extends DatabaseCommand implements InitCarrierInterface, ProducerInterface
28
{
29
    use ContextTrait;
30
    use ErrorTrait;
0 ignored issues
show
Bug introduced by
The trait Cycle\ORM\Command\Traits\ErrorTrait requires the property $waitScope which is not provided by Cycle\ORM\Command\Database\Insert.
Loading history...
31
32
    // Special identifier to forward insert key into
33
    public const INSERT_ID = '@lastInsertID';
34
35
    /** @var array */
36
    protected $data;
37
38
    /** @var string|null */
39
    protected $primaryKey;
40
41
    /** @var ConsumerInterface[] */
42
    protected $consumers = [];
43
44
    /**
45
     * @param DatabaseInterface $db
46
     * @param string            $table
47
     * @param array             $data
48
     * @param string|null       $primaryKey
49
     */
50
    public function __construct(
51
        DatabaseInterface $db,
52
        string $table,
53
        array $data = [],
54
        string $primaryKey = null
55
    ) {
56
        parent::__construct($db, $table);
57
        $this->data = $data;
58
        $this->primaryKey = $primaryKey;
59
    }
60
61
    /**
62
     * @inheritdoc
63
     */
64
    public function isReady(): bool
65
    {
66
        return $this->waitContext === [];
67
    }
68
69
    /**
70
     * @inheritdoc
71
     *
72
     * Triggers only after command execution!
73
     */
74
    public function forward(
75
        string $key,
76
        ConsumerInterface $consumer,
77
        string $target,
78
        bool $trigger = false,
79
        int $stream = ConsumerInterface::DATA
80
    ): void {
81
        if ($trigger) {
82
            throw new CommandException('Insert command can only forward keys after the execution');
83
        }
84
85
        $this->consumers[$key][] = [$consumer, $target, $stream];
86
    }
87
88
    /**
89
     * @inheritdoc
90
     */
91
    public function register(string $key, $value, bool $fresh = false, int $stream = self::DATA): void
92
    {
93
        if ($fresh || $value !== null) {
94
            $this->freeContext($key);
95
        }
96
97
        $this->setContext($key, $value);
98
    }
99
100
    /**
101
     * Insert values, context not included.
102
     *
103
     * @return array
104
     */
105
    public function getData(): array
106
    {
107
        return array_merge($this->data, $this->context);
108
    }
109
110
    /**
111
     * Insert data into associated table.
112
     */
113
    public function execute(): void
114
    {
115
        $data = $this->getData();
116
117
        $insert = $this->db->insert($this->table)->values($data);
0 ignored issues
show
Bug introduced by
It seems like $this->table can also be of type null; however, parameter $table of Spiral\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

117
        $insert = $this->db->insert(/** @scrutinizer ignore-type */ $this->table)->values($data);
Loading history...
118
        if ($this->primaryKey !== null && $insert instanceof PostgresInsertQuery) {
119
            $insert->returning($this->primaryKey);
120
        }
121
122
        $insertID = $insert->run();
123
124
        foreach ($this->consumers as $key => $consumers) {
125
            $fresh = true;
126
            if ($key === self::INSERT_ID) {
127
                $value = $insertID;
128
            } else {
129
                $value = $data[$key] ?? null;
130
            }
131
132
            foreach ($consumers as $id => $consumer) {
133
                /** @var ConsumerInterface $cn */
134
                $cn = $consumer[0];
135
136
                $cn->register($consumer[1], $value, $fresh, $consumer[2]);
137
138
                if ($key !== self::INSERT_ID) {
139
                    // primary key is always delivered as fresh
140
                    $fresh = false;
141
                }
142
            }
143
        }
144
145
        parent::execute();
146
    }
147
}
148