Completed
Push — master ( 31b5db...524ecf )
by Michael
03:26
created

PreserverTrait::getPreserveTos()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 8
ccs 0
cts 8
cp 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
crap 6
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * Contains PreserverTrait Trait.
5
 *
6
 * PHP version 7.0+
7
 *
8
 * LICENSE:
9
 * This file is part of Yet Another Php Eve Api Library also know as Yapeal
10
 * which can be used to access the Eve Online API data and place it into a
11
 * database.
12
 * Copyright (C) 2014-2016 Michael Cummings
13
 *
14
 * This program is free software: you can redistribute it and/or modify it
15
 * under the terms of the GNU Lesser General Public License as published by the
16
 * Free Software Foundation, either version 3 of the License, or (at your
17
 * option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful, but WITHOUT
20
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
22
 * for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public License
25
 * along with this program. If not, see
26
 * <http://spdx.org/licenses/LGPL-3.0.html>.
27
 *
28
 * You should be able to find a copy of this license in the COPYING-LESSER.md
29
 * file. A copy of the GNU GPL should also be available in the COPYING.md file. 
30
 *
31
 * @copyright 2014-2016 Michael Cummings
32
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
33
 * @author    Michael Cummings <[email protected]>
34
 */
35
namespace Yapeal\Sql;
36
37
use Yapeal\Event\EveApiEventInterface;
38
use Yapeal\Event\MediatorInterface;
39
use Yapeal\Log\Logger;
40
41
/**
42
 * Trait PreserverTrait
43
 *
44
 * @method CommonSqlQueries getCsq()
45
 * @method \PDO getPdo()
46
 * @method MediatorInterface getYem()
47
 */
48
trait PreserverTrait
49
{
50
    /**
51
     * @return string[]
52
     * @throws \LogicException
53
     */
54
    public function getPreserveTos(): array
55
    {
56
        if (0 === count($this->preserveTos)) {
57
            $mess = 'Tried to access preserveTos before it was set';
58
            throw new \LogicException($mess);
59
        }
60
        return $this->preserveTos;
61
    }
62
    /**
63
     * @param EveApiEventInterface $event
64
     * @param string               $eventName
65
     * @param MediatorInterface    $yem
66
     *
67
     * @return EveApiEventInterface
68
     * @throws \DomainException
69
     * @throws \InvalidArgumentException
70
     * @throws \LogicException
71
     */
72
    public function preserveEveApi(
73
        EveApiEventInterface $event,
74
        string $eventName,
75
        MediatorInterface $yem
76
    ): EveApiEventInterface
77
    {
78
        if (!$this->shouldPreserve()) {
79
            return $event;
80
        }
81
        $this->setYem($yem);
0 ignored issues
show
Bug introduced by
It seems like setYem() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
82
        $data = $event->getData();
83
        $xml = $data->getEveApiXml();
84
        if (false === $xml) {
85
            return $event->setHandledSufficiently();
86
        }
87
        $this->getYem()
88
            ->triggerLogEvent('Yapeal.Log.log',
89
                Logger::DEBUG,
90
                $this->getReceivedEventMessage($data, $eventName, __CLASS__));
1 ignored issue
show
Bug introduced by
It seems like getReceivedEventMessage() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
91
        $this->getPdo()
92
            ->beginTransaction();
93
        try {
94
            foreach ($this->getPreserveTos() as $preserveTo) {
95
                $this->$preserveTo($data);
96
            }
97
            $this->getPdo()
98
                ->commit();
99
        } catch (\PDOException $exc) {
100
            $mess = 'Failed to upsert data of';
101
            $this->getYem()
102
                ->triggerLogEvent('Yapeal.Log.log',
103
                    Logger::WARNING,
104
                    $this->createEveApiMessage($mess, $data),
1 ignored issue
show
Bug introduced by
It seems like createEveApiMessage() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
105
                    ['exception' => $exc]);
106
            $this->getPdo()
107
                ->rollBack();
108
            return $event;
109
        }
110
        $this->getYem()
111
            ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $this->getFinishedEventMessage($data, $eventName));
1 ignored issue
show
Bug introduced by
It seems like getFinishedEventMessage() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
112
        return $event->setHandledSufficiently();
113
    }
114
    /**
115
     * Turn on or off preserving of Eve API data by this preserver.
116
     *
117
     * Allows class to stay registered for events but be enabled or disabled during runtime.
118
     *
119
     * @param boolean $value
120
     *
121
     * @return $this Fluent interface
122
     */
123
    public function setPreserve(bool $value = true)
124
    {
125
        $this->preserve = (boolean)$value;
126
        return $this;
127
    }
128
    /**
129
     * @param \SimpleXMLElement[] $rows
130
     * @param array               $columnDefaults
131
     * @param string              $tableName
132
     *
133
     * @return self Fluent interface.
134
     * @throws \DomainException
135
     * @throws \InvalidArgumentException
136
     * @throws \LogicException
137
     */
138
    protected function attributePreserveData(array $rows, array $columnDefaults, string $tableName)
139
    {
140
        $maxRowCount = 1000;
141
        if (0 === count($rows)) {
142
            return $this;
143
        }
144
        $rows = array_chunk($rows, $maxRowCount, true);
145
        $columnNames = array_keys($columnDefaults);
146
        foreach ($rows as $chunk) {
147
            $this->flush($this->processXmlRows($columnDefaults, $chunk), $columnNames, $tableName);
148
        }
149
        return $this;
150
    }
151
    /**
152
     * @param string[] $columns
153
     * @param string[] $columnNames
154
     * @param string   $tableName
155
     *
156
     * @return self Fluent interface.
157
     * @throws \DomainException
158
     * @throws \InvalidArgumentException
159
     * @throws \LogicException
160
     */
161
    protected function flush(array $columns, array $columnNames, string $tableName)
162
    {
163
        if (0 === count($columns)) {
164
            return $this;
165
        }
166
        $rowCount = count($columns) / count($columnNames);
167
        $mess = sprintf('Have %1$s row(s) to upsert into %2$s table', $rowCount, $tableName);
168
        $this->getYem()
169
            ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $mess);
170
        $sql = $this->getCsq()
171
            ->getUpsert($tableName, $columnNames, $rowCount);
172
        $mess = preg_replace('/(,\(\?(?:,\?)*\))+/', ',...', $sql);
173
        $this->getYem()
174
            ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $mess);
175
        $mess = implode(',', $columns);
176
        if (512 < strlen($mess)) {
177
            $mess = substr($mess, 0, 512) . '...';
178
        }
179
        $this->getYem()
180
            ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $mess);
181
        $this->getPdo()
182
            ->prepare($sql)
183
            ->execute($columns);
184
        return $this;
185
    }
186
    /**
187
     * @param array               $columnDefaults
188
     * @param \SimpleXMLElement[] $rows
189
     *
190
     * @return array
191
     */
192
    protected function processXmlRows(array $columnDefaults, array $rows): array
193
    {
194
        $columns = [];
195
        foreach ($rows as $row) {
196
            // Replace empty values with any existing defaults.
197
            foreach ($columnDefaults as $key => $value) {
198
                if (null === $value || '' !== (string)$row[$key]) {
199
                    $columns[] = (string)$row[$key];
200
                    continue;
201
                }
202
                $columns[] = (string)$value;
203
            }
204
        }
205
        return $columns;
206
    }
207
    /**
208
     * @param \SimpleXMLElement[] $elements
209
     * @param array               $columnDefaults
210
     * @param string              $tableName
211
     *
212
     * @return self Fluent interface.
213
     * @throws \DomainException
214
     * @throws \InvalidArgumentException
215
     * @throws \LogicException
216
     */
217
    protected function valuesPreserveData(array $elements, array $columnDefaults, string $tableName)
218
    {
219
        if (0 === count($elements)) {
220
            return $this;
221
        }
222
        $eleCount = 0;
223
        foreach ($elements as $element) {
224
            $columnName = $element->getName();
225
            if (!array_key_exists($columnName, $columnDefaults)) {
226
                continue;
227
            }
228
            ++$eleCount;
229
            if ('' !== (string)$element || null === $columnDefaults[$columnName]) {
230
                $columnDefaults[$columnName] = (string)$element;
231
            }
232
        }
233
        $required = array_reduce($columnDefaults,
234
            function ($carry, $item) {
235
                return $carry + (int)(null === $item);
236
            },
237
            0);
238
        if ($required > $eleCount) {
239
            return $this;
240
        }
241
        uksort($columnDefaults,
242
            function ($alpha, $beta) {
243
                return strtolower($alpha) <=> strtolower($beta);
244
            });
245
        return $this->flush(array_values($columnDefaults), array_keys($columnDefaults), $tableName);
246
    }
247
    /**
248
     * @var string[] preserveTos
249
     */
250
    protected $preserveTos = [];
251
    /**
252
     * @return bool
253
     */
254
    private function shouldPreserve(): bool
255
    {
256
        return $this->preserve;
257
    }
258
    /**
259
     * @var bool $preserve
260
     */
261
    private $preserve = true;
262
}
263