Completed
Push — master ( 75748b...36048b )
by Michael
06:58
created

PreserverTrait::flush()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 25
rs 8.8571
cc 3
eloc 21
nc 3
nop 3
1
<?php
2
/**
3
 * Contains PreserverTrait Trait.
4
 *
5
 * PHP version 5.5
6
 *
7
 * LICENSE:
8
 * This file is part of Yet Another Php Eve Api Library also know as Yapeal
9
 * which can be used to access the Eve Online API data and place it into a
10
 * database.
11
 * Copyright (C) 2014-2016 Michael Cummings
12
 *
13
 * This program is free software: you can redistribute it and/or modify it
14
 * under the terms of the GNU Lesser General Public License as published by the
15
 * Free Software Foundation, either version 3 of the License, or (at your
16
 * option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful, but WITHOUT
19
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
21
 * for more details.
22
 *
23
 * You should have received a copy of the GNU Lesser General Public License
24
 * along with this program. If not, see
25
 * <http://www.gnu.org/licenses/>.
26
 *
27
 * You should be able to find a copy of this license in the LICENSE.md file. A
28
 * copy of the GNU GPL should also be available in the GNU-GPL.md file.
29
 *
30
 * @copyright 2014-2016 Michael Cummings
31
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
32
 * @author    Michael Cummings <[email protected]>
33
 */
34
namespace Yapeal\Sql;
35
36
use Yapeal\Event\EveApiEventInterface;
37
use Yapeal\Event\MediatorInterface;
38
use Yapeal\Log\Logger;
39
40
/**
41
 * Trait PreserverTrait
42
 */
43
trait PreserverTrait
44
{
45
    /**
46
     * @return \string[]
47
     * @throws \LogicException
48
     */
49
    public function getPreserveTos()
50
    {
51
        if (0 === count($this->preserveTos)){
52
            $mess = 'Tried to access preserveTos before it was set';
53
            throw new \LogicException($mess);
54
        }
55
        return $this->preserveTos;
56
    }
57
    /** @noinspection MoreThanThreeArgumentsInspection */
58
    /**
59
     * @param \SimpleXMLElement[]|string $rows
60
     * @param array  $columnDefaults
61
     * @param string $tableName
62
     * @param string $xPath
63
     *
64
     * @return self Fluent interface.
65
     * @throws \DomainException
66
     * @throws \InvalidArgumentException
67
     * @throws \LogicException
68
     */
69
    protected function attributePreserveData($rows, array $columnDefaults, $tableName, $xPath = '//row')
0 ignored issues
show
Unused Code introduced by
The parameter $xPath is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
70
    {
71
        $maxRowCount = 1000;
72
        if (is_string($rows) || 0 === count($rows)) {
73
            return $this;
74
        }
75
        $rows = array_chunk($rows, $maxRowCount, true);
76
        $columnNames = array_keys($columnDefaults);
77
        foreach ($rows as $chunk) {
78
            $this->flush($this->processXmlRows($columnDefaults, $chunk), $columnNames, $tableName);
79
        }
80
        return $this;
81
    }
82
    /**
83
     * @param string[] $columns
84
     * @param string[] $columnNames
85
     * @param string   $tableName
86
     *
87
     * @return self Fluent interface.
88
     * @throws \DomainException
89
     * @throws \InvalidArgumentException
90
     * @throws \LogicException
91
     */
92
    protected function flush(array $columns, array $columnNames, $tableName)
93
    {
94
        if (0 === count($columns)) {
95
            return $this;
96
        }
97
        $rowCount = count($columns) / count($columnNames);
98
        $mess = sprintf('Have %1$s row(s) to upsert into %2$s table', $rowCount, $tableName);
99
        $this->getYem()
100
             ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $mess);
101
        $sql = $this->getCsq()
102
                    ->getUpsert($tableName, $columnNames, $rowCount);
103
        $mess = preg_replace('/(,\(\?(?:,\?)*\))+/', ',...', $sql);
104
        $this->getYem()
105
             ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $mess);
106
        $mess = implode(',', $columns);
107
        if (512 < strlen($mess)) {
108
            $mess = substr($mess, 0, 512) . '...';
109
        }
110
        $this->getYem()
111
             ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $mess);
112
        $this->getPdo()
113
             ->prepare($sql)
114
             ->execute($columns);
115
        return $this;
116
    }
117
    /**
118
     * @return \Yapeal\Sql\CommonSqlQueries
119
     */
120
    abstract protected function getCsq();
121
    /**
122
     * @return \PDO
123
     */
124
    abstract protected function getPdo();
125
    /**
126
     * @return \Yapeal\Event\MediatorInterface
127
     */
128
    abstract protected function getYem();
129
    /**
130
     * @param array               $columnDefaults
131
     * @param \SimpleXMLElement[] $rows
132
     *
133
     * @return array
134
     */
135
    protected function processXmlRows(array $columnDefaults, array $rows)
136
    {
137
        $columns = [];
138
        foreach ($rows as $row) {
139
            // Replace empty values with any existing defaults.
140
            foreach ($columnDefaults as $key => $value) {
141
                if (null === $value || '' !== (string)$row[$key]) {
142
                    $columns[] = (string)$row[$key];
143
                    continue;
144
                }
145
                $columns[] = (string)$value;
146
            }
147
        }
148
        return $columns;
149
    }
150
    /** @noinspection MoreThanThreeArgumentsInspection */
151
    /**
152
     * @param string $xml
153
     * @param array  $columnDefaults
154
     * @param string $tableName
155
     * @param string $xPath
156
     *
157
     * @return self Fluent interface.
158
     * @throws \DomainException
159
     * @throws \InvalidArgumentException
160
     * @throws \LogicException
161
     */
162
    protected function valuesPreserveData(
163
        $xml,
164
        array $columnDefaults,
165
        $tableName,
166
        $xPath = '//result/child::*[not(*|@*|self::dataTime)]'
167
    ) {
168
        $elements = (new \SimpleXMLElement($xml))->xpath($xPath);
169
        if (0 === count($elements)) {
170
            return $this;
171
        }
172
        $columns = [];
173
        foreach ($elements as $element) {
174
            $columnName = $element->getName();
175
            if (!array_key_exists($columnName, $columnDefaults)) {
176
                continue;
177
            }
178
            if ('' !== (string)$element || null === $columnDefaults[$columnName]) {
179
                $columns[$columnName] = (string)$element;
180
                continue;
181
            }
182
            $columns[$columnName] = $columnDefaults[$columnName];
183
        }
184
        if (count($columnDefaults) !== count($columns)) {
185
            return $this;
186
        }
187
        ksort($columns);
188
        return $this->flush(array_values($columns), array_keys($columns), $tableName);
189
    }
190
    /**
191
     * @param EveApiEventInterface $event
192
     * @param string               $eventName
193
     * @param MediatorInterface    $yem
194
     *
195
     * @return EveApiEventInterface
196
     * @throws \DomainException
197
     * @throws \InvalidArgumentException
198
     * @throws \LogicException
199
     */
200
    public function preserveEveApi(EveApiEventInterface $event, $eventName, MediatorInterface $yem)
201
    {
202
        $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...
203
        $data = $event->getData();
204
        $xml = $data->getEveApiXml();
205
        if (false === $xml) {
206
            return $event->setHandledSufficiently();
207
        }
208
        $this->getYem()
209
             ->triggerLogEvent(
210
                 'Yapeal.Log.log',
211
                 Logger::DEBUG,
212
                 $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...
213
             );
214
        $this->getPdo()
215
             ->beginTransaction();
216
        try {
217
            foreach ($this->getPreserveTos() as $preserveTo) {
218
                $this->$preserveTo($data);
219
            }
220
            $this->getPdo()
221
                 ->commit();
222
        } catch (\PDOException $exc) {
223
            $mess = 'Failed to upsert data of';
224
            $this->getYem()
225
                 ->triggerLogEvent(
226
                     'Yapeal.Log.log',
227
                     Logger::WARNING,
228
                     $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...
229
                     ['exception' => $exc]
230
                 );
231
            $this->getPdo()
232
                 ->rollBack();
233
            return $event;
234
        }
235
        return $event->setHandledSufficiently();
236
    }
237
    /**
238
     * @var string[] preserveTos
239
     */
240
    protected $preserveTos = [];
241
}
242