GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 75bdf9...8faa57 )
by joseph
83:56 queued 81:04
created

BulkEntityUpdater::ensureNotBinaryId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 5
ccs 3
cts 4
cp 0.75
crap 2.0625
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\Entity\Savers;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\PrimaryKey\UuidFieldTrait;
7
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\EntityInterface;
8
use EdmondsCommerce\DoctrineStaticMeta\Entity\Savers\BulkEntityUpdater\BulkEntityUpdateHelper;
9
use EdmondsCommerce\DoctrineStaticMeta\Schema\MysqliConnectionFactory;
10
use ts\Reflection\ReflectionClass;
11
12
class BulkEntityUpdater extends AbstractBulkProcess
13
{
14
    /**
15
     * @var BulkEntityUpdateHelper
16
     */
17
    private $extractor;
18
    /**
19
     * @var string
20
     */
21
    private $tableName;
22
    /**
23
     * @var string
24
     */
25
    private $entityFqn;
26
    /**
27
     * @var \mysqli
28
     */
29
    private $mysqli;
30
    /**
31
     * This holds the bulk SQL query
32
     *
33
     * @var string
34
     */
35
    private $query;
36
37
    /**
38
     * @var float
39
     */
40
    private $requireAffectedRatio = 1.0;
41
42
    /**
43
     * @var int
44
     */
45
    private $totalAffectedRows = 0;
46
47 5
    public function __construct(EntityManagerInterface $entityManager, MysqliConnectionFactory $mysqliConnectionFactory)
48
    {
49 5
        parent::__construct($entityManager);
50 5
        $this->mysqli = $mysqliConnectionFactory->createFromEntityManager($entityManager);
51 5
    }
52
53
    /**
54
     * @param float $requireAffectedRatio
55
     *
56
     * @return BulkEntityUpdater
57
     */
58 2
    public function setRequireAffectedRatio(float $requireAffectedRatio): BulkEntityUpdater
59
    {
60 2
        $this->requireAffectedRatio = $requireAffectedRatio;
61
62 2
        return $this;
63
    }
64
65
    public function addEntityToSave(EntityInterface $entity)
66
    {
67
        if (false === $entity instanceof $this->entityFqn) {
68
            throw new \RuntimeException('You can only bulk save a single entity type, currently saving ' .
69
                                        $this->entityFqn .
70
                                        ' but you are trying to save ' .
71
                                        \get_class($entity));
72
        }
73
        parent::addEntityToSave($entity);
74
    }
75
76 3
    public function setExtractor(BulkEntityUpdateHelper $extractor): void
77
    {
78 3
        $this->extractor = $extractor;
79 3
        $this->tableName = $extractor->getTableName();
80 3
        $this->entityFqn = $extractor->getEntityFqn();
81 3
        $this->ensureNotBinaryId();
82 3
    }
83
84 3
    private function ensureNotBinaryId()
85
    {
86 3
        $traits = (new ReflectionClass($this->entityFqn))->getTraits();
87 3
        if (array_key_exists(UuidFieldTrait::class, $traits)) {
88
            throw new \RuntimeException(' you can not use this updater on entities that have binary keys');
89
        }
90 3
    }
91
92 2
    public function startBulkProcess(): AbstractBulkProcess
93
    {
94 2
        if (!$this->extractor instanceof BulkEntityUpdateHelper) {
0 ignored issues
show
introduced by
$this->extractor is always a sub-type of EdmondsCommerce\Doctrine...\BulkEntityUpdateHelper. If $this->extractor can have other possible types, add them to src/Entity/Savers/BulkEntityUpdater.php:15.
Loading history...
95
            throw new \RuntimeException(
96
                'You must call setExtractor with your extractor logic before starting the process. '
97
                . 'Note - a small anonymous class would be ideal'
98
            );
99
        }
100 2
        $this->resetQuery();
101
102 2
        return parent::startBulkProcess();
103
    }
104
105 3
    private function resetQuery()
106
    {
107 3
        $this->query = '';
108 3
    }
109
110
    /**
111
     * @return int
112
     */
113 1
    public function getTotalAffectedRows(): int
114
    {
115 1
        return $this->totalAffectedRows;
116
    }
117
118 3
    protected function doSave(): void
119
    {
120 3
        foreach ($this->entitiesToSave as $entity) {
121 3
            if (!$entity instanceof $this->entityFqn || !$entity instanceof EntityInterface) {
122
                throw new \RuntimeException(
123
                    'You can only bulk save a single entity type, currently saving ' . $this->entityFqn .
124
                    ' but you are trying to save ' . \get_class($entity)
125
                );
126
            }
127 3
            $this->appendToQuery(
128 3
                $this->convertExtractedToSqlRow(
129 3
                    $this->extractor->extract($entity)
130
                )
131
            );
132
        }
133 3
        $this->runQuery();
134 2
        $this->resetQuery();
135 2
    }
136
137 3
    private function appendToQuery(string $sql)
138
    {
139 3
        $this->query .= "\n$sql";
140 3
    }
141
142
    /**
143
     * Take the extracted array and build an update query
144
     *
145
     * @param array $extracted
146
     *
147
     * @return string
148
     */
149 3
    private function convertExtractedToSqlRow(array $extracted): string
150
    {
151 3
        if ([] === $extracted) {
152
            throw new \RuntimeException('Extracted array is empty in ' . __METHOD__);
153
        }
154 3
        $primaryKeyCol = null;
155 3
        $primaryKey    = null;
156 3
        $sql           = "update `{$this->tableName}` set ";
157 3
        $sqls          = [];
158 3
        foreach ($extracted as $key => $value) {
159 3
            if (null === $primaryKeyCol) {
160 3
                $primaryKeyCol = $key;
161 3
                $primaryKey    = $value;
162 3
                continue;
163
            }
164 3
            $value  = $this->mysqli->escape_string((string)$value);
165 3
            $sqls[] = "`$key` = '$value'";
166
        }
167 3
        $sql .= implode(",\n", $sqls);
168 3
        $sql .= " where `$primaryKeyCol` = '$primaryKey'; ";
169
170 3
        return $sql;
171
    }
172
173 3
    private function runQuery(): void
174
    {
175 3
        if ('' === $this->query) {
176
            return;
177
        }
178 3
        $this->query = "
179
            SET FOREIGN_KEY_CHECKS = 0; 
180
            SET UNIQUE_CHECKS = 0;
181 3
            SET AUTOCOMMIT = 0; {$this->query} COMMIT;            
182
            SET FOREIGN_KEY_CHECKS = 1; 
183
            SET UNIQUE_CHECKS = 1; ";
184 3
        $this->mysqli->multi_query($this->query);
185 3
        $affectedRows = 0;
186
        do {
187 3
            $affectedRows += max($this->mysqli->affected_rows, 0);
188 3
        } while ($this->mysqli->more_results() && $this->mysqli->next_result());
189 3
        if ($affectedRows < count($this->entitiesToSave) * $this->requireAffectedRatio) {
190 1
            throw new \RuntimeException(
191 1
                'Affected rows count of ' . $affectedRows .
192 1
                ' does match the expected count of entitiesToSave ' . count($this->entitiesToSave)
193
            );
194
        }
195 2
        $this->totalAffectedRows += $affectedRows;
196 2
    }
197
}
198