Completed
Push — master ( 598fe1...4a905b )
by Michael
03:41
created

Transformer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * Contains Transformer class.
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) 2015-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 2015-2016 Michael Cummings
32
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
33
 * @author    Michael Cummings <[email protected]>
34
 */
35
namespace Yapeal\Xsl;
36
37
use Yapeal\Event\EveApiEventEmitterTrait;
38
use Yapeal\Event\EveApiEventInterface;
39
use Yapeal\Event\MediatorInterface;
40
use Yapeal\Exception\YapealFileSystemException;
41
use Yapeal\FileSystem\RelativeFileSearchTrait;
42
use Yapeal\Log\Logger;
43
use Yapeal\Xml\EveApiReadWriteInterface;
44
45
/**
46
 * Class Transformer
47
 */
48
class Transformer implements TransformerInterface
49
{
50
    use EveApiEventEmitterTrait, RelativeFileSearchTrait;
51
    /**
52
     * Transformer Constructor.
53
     *
54
     * @param string $dir Base directory where Eve API XSL files can be found.
55
     */
56 1
    public function __construct(string $dir = __DIR__)
57
    {
58 1
        $this->setRelativeBaseDir($dir . '/');
59
    }
60
    /**
61
     * @param EveApiEventInterface $event
62
     * @param string               $eventName
63
     * @param MediatorInterface    $yem
64
     *
65
     * @return EveApiEventInterface|\EventMediator\EventInterface
66
     * @throws \DomainException
67
     * @throws \InvalidArgumentException
68
     * @throws \LogicException
69
     */
70
    public function transformEveApi(
71
        EveApiEventInterface $event,
72
        string $eventName,
73
        MediatorInterface $yem
74
    ): EveApiEventInterface
75
    {
76
        $this->setYem($yem);
77
        $data = $event->getData();
78
        $yem->triggerLogEvent('Yapeal.Log.log',
79
            Logger::DEBUG,
80
            $this->getReceivedEventMessage($data, $eventName, __CLASS__));
81
        try {
82
            $xslName = $this->findRelativeFileWithPath(ucfirst($data->getEveApiSectionName()),
83
                $data->getEveApiName(),
84
                'xsl');
85
        } catch (YapealFileSystemException $exc) {
86
            $mess = 'Failed to find accessible XSL transform file during';
87
            $yem->triggerLogEvent('Yapeal.Log.log',
88
                Logger::WARNING,
89
                $this->createEventMessage($mess, $data, $eventName),
90
                ['exception' => $exc]);
91
            return $event;
92
        }
93
        $mess = sprintf('Using %1$s file to transform', $xslName);
94
        $yem->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $this->createEveApiMessage($mess, $data));
95
        $xml = $this->addYapealProcessingInstructionToXml($data)
96
            ->performTransform($xslName, $data);
97
        if (false === $xml) {
98
            $mess = 'Failed to transform xml during';
99
            $yem->triggerLogEvent('Yapeal.Log.log',
100
                Logger::WARNING,
101
                $this->createEventMessage($mess, $data, $eventName));
102
            return $event;
103
        }
104
        $xml = (new \tidy())->repairString($xml, $this->tidyConfig, 'utf8');
105
        return $event->setData($data->setEveApiXml($xml))
106
            ->setHandledSufficiently();
107
    }
108
    /**
109
     * Adds Processing Instruction to XML containing json encoding of any post used during retrieve.
110
     *
111
     * NOTE: This use to be done directly in the network retriever but felt modifying the XML like that belonged in
112
     * transform instead.
113
     *
114
     * @param EveApiReadWriteInterface $data
115
     *
116
     * @return \Yapeal\Xsl\Transformer Fluent interface.
0 ignored issues
show
Documentation introduced by
Should the return type not be \self?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
117
     * @throws \InvalidArgumentException
118
     * @throws \LogicException
119
     */
120
    private function addYapealProcessingInstructionToXml(EveApiReadWriteInterface $data): self
121
    {
122
        $xml = $data->getEveApiXml();
123
        if (false === $xml) {
124
            return $this;
125
        }
126
        $arguments = $data->getEveApiArguments();
127
        if (!empty($arguments['vCode'])) {
128
            $arguments['vCode'] = substr($arguments['vCode'], 0, 8) . '...';
129
        }
130
        if (!in_array($data->getEveApiName(), ['accountBalance', 'walletJournal', 'walletTransactions'], true)) {
131
            unset($arguments['accountKey']);
132
        }
133
        unset($arguments['mask'], $arguments['rowCount']);
134
        ksort($arguments);
135
        $json = json_encode($arguments);
136
        $xml = str_replace(["encoding='UTF-8'?>\r\n<eveapi", "encoding='UTF-8'?>\n<eveapi"],
137
            [
138
                "encoding='UTF-8'?>\r\n<?yapeal.parameters.json " . $json . "?>\r\n<eveapi",
139
                "encoding='UTF-8'?>\n<?yapeal.parameters.json " . $json . "?>\n<eveapi"
140
            ],
141
            $xml);
142
        $data->setEveApiXml($xml);
143
        return $this;
144
    }
145
    /**
146
     * @return \DOMDocument
147
     */
148
    private function getDom(): \DOMDocument
149
    {
150
        if (null === $this->dom) {
151
            $this->dom = new \DOMDocument();
152
        }
153
        return $this->dom;
154
    }
155
    /**
156
     * @return \XSLTProcessor
157
     */
158
    private function getXslt(): \XSLTProcessor
159
    {
160
        if (null === $this->xslt) {
161
            $this->xslt = new \XSLTProcessor();
162
        }
163
        return $this->xslt;
164
    }
165
    /**
166
     * @param string                   $xslName
167
     * @param EveApiReadWriteInterface $data
168
     *
169
     * @return false|string
170
     * @throws \DomainException
171
     * @throws \InvalidArgumentException
172
     * @throws \LogicException
173
     */
174
    private function performTransform(string $xslName, EveApiReadWriteInterface $data)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
175
    {
176
        libxml_clear_errors();
177
        libxml_use_internal_errors(true);
178
        libxml_clear_errors();
179
        $xslt = $this->getXslt();
180
        $dom = $this->getDom();
181
        $dom->load($xslName);
182
        $xslt->importStylesheet($dom);
183
        $result = false;
184
        try {
185
            $result = $xslt->transformToXml(new \SimpleXMLElement($data->getEveApiXml()));
186
        } catch (\Exception $exc) {
187
            $mess = 'XML cause SimpleXMLElement exception in';
188
            $this->getYem()
189
                ->triggerLogEvent('Yapeal.log.log',
190
                    Logger::WARNING,
191
                    $this->createEveApiMessage($mess, $data),
192
                    ['exception' => $exc]);
193
        }
194
        if (false === $result) {
195
            /**
196
             * @var array $errors
197
             */
198
            $errors = libxml_get_errors();
199
            if (0 !== count($errors)) {
200
                foreach ($errors as $error) {
201
                    $this->getYem()
202
                        ->triggerLogEvent('Yapeal.Log.log', Logger::NOTICE, $error->message);
203
                }
204
            }
205
            $apiName = $data->getEveApiName();
206
            $data->setEveApiName('Untransformed_' . $apiName);
207
            // Cache error causing XML.
208
            $this->emitEvents($data, 'preserve', 'Yapeal.Xml.Error');
209
            $data->setEveApiName($apiName);
210
        }
211
        libxml_clear_errors();
212
        libxml_use_internal_errors(false);
213
        libxml_clear_errors();
214
        return $result;
215
    }
216
    /**
217
     * @var \DOMDocument $dom
218
     */
219
    private $dom;
220
    /**
221
     * Holds tidy config settings.
222
     *
223
     * @var array $tidyConfig
224
     */
225
    private $tidyConfig = [
226
        'indent' => true,
227
        'indent-spaces' => 4,
228
        'input-xml' => true,
229
        'newline' => 'LF',
230
        'output-xml' => true,
231
        'wrap' => '1000'
232
    ];
233
    /**
234
     * @var \XSLTProcessor $xslt
235
     */
236
    private $xslt;
237
}
238