Completed
Push — master ( 2cff5f...81de03 )
by Michael
03:19
created

Transformer::transformEveApi()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 1 Features 0
Metric Value
c 6
b 1
f 0
dl 0
loc 25
rs 8.8571
cc 3
eloc 21
nc 3
nop 3
1
<?php
2
/**
3
 * Contains Transformer class.
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) 2015-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 2015-2016 Michael Cummings
31
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
32
 * @author    Michael Cummings <[email protected]>
33
 */
34
namespace Yapeal\Xsl;
35
36
use Yapeal\Event\EveApiEventEmitterTrait;
37
use Yapeal\Event\EveApiEventInterface;
38
use Yapeal\Event\MediatorInterface;
39
use Yapeal\FileSystem\RelativeFileSearchTrait;
40
use Yapeal\Log\Logger;
41
use Yapeal\Xml\EveApiReadWriteInterface;
42
43
/**
44
 * Class Transformer
45
 */
46
class Transformer implements TransformerInterface
47
{
48
    use EveApiEventEmitterTrait, RelativeFileSearchTrait;
49
    /**
50
     * Transformer Constructor.
51
     *
52
     * @param string $dir Base directory where Eve API XSL files can be found.
53
     */
54
    public function __construct($dir = __DIR__)
55
    {
56
        $this->setRelativeBaseDir($dir . '/');
57
    }
58
    /**
59
     * @param EveApiEventInterface $event
60
     * @param string               $eventName
61
     * @param MediatorInterface    $yem
62
     *
63
     * @return EveApiEventInterface
64
     * @throws \DomainException
65
     * @throws \InvalidArgumentException
66
     * @throws \LogicException
67
     */
68
    public function transformEveApi(EveApiEventInterface $event, $eventName, MediatorInterface $yem)
69
    {
70
        $this->setYem($yem);
71
        $data = $event->getData();
72
        $this->getYem()
73
            ->triggerLogEvent('Yapeal.Log.log',
74
                Logger::DEBUG,
75
                $this->getReceivedEventMessage($data, $eventName, __CLASS__));
76
        $fileName = $this->findEveApiFile($data->getEveApiSectionName(), $data->getEveApiName(), 'xsl');
77
        if ('' === $fileName) {
78
            return $event;
79
        }
80
        $xml = $this->addYapealProcessingInstructionToXml($data)
81
            ->performTransform($fileName, $data);
82
        if (false === $xml) {
83
            $mess = 'Failed to transform xml during';
84
            $yem->triggerLogEvent('Yapeal.Log.log',
85
                Logger::WARNING,
86
                $this->createEventMessage($mess, $data, $eventName));
87
            return $event;
88
        }
89
        $xml = (new \tidy())->repairString($xml, $this->tidyConfig, 'utf8');
90
        return $event->setData($data->setEveApiXml($xml))
91
            ->eventHandled();
92
    }
93
    /**
94
     * Adds Processing Instruction to XML containing json encoding of any post used during retrieve.
95
     *
96
     * NOTE: This use to be done directly in the network retriever but felt modifying the XML like that belonged in
97
     * transform instead.
98
     *
99
     * @param EveApiReadWriteInterface $data
100
     *
101
     * @return self Fluent interface.
102
     * @throws \LogicException
103
     * @throws \InvalidArgumentException
104
     */
105
    protected function addYapealProcessingInstructionToXml(EveApiReadWriteInterface $data)
106
    {
107
        $xml = $data->getEveApiXml();
108
        if (false === $xml) {
109
            return $this;
110
        }
111
        $arguments = $data->getEveApiArguments();
112
        if (!empty($arguments['vCode'])) {
113
            $arguments['vCode'] = substr($arguments['vCode'], 0, 8) . '...';
114
        }
115
        if (!in_array($data->getEveApiName(), ['accountBalance', 'walletJournal', 'walletTransactions'], true)) {
116
            unset($arguments['accountKey']);
117
        }
118
        unset($arguments['mask'], $arguments['rowCount']);
119
        ksort($arguments);
120
        $json = json_encode($arguments);
121
        $xml = str_replace(["encoding='UTF-8'?>\r\n<eveapi", "encoding='UTF-8'?>\n<eveapi"],
122
            [
123
                "encoding='UTF-8'?>\r\n<?yapeal.parameters.json " . $json . "?>\r\n<eveapi",
124
                "encoding='UTF-8'?>\n<?yapeal.parameters.json " . $json . "?>\n<eveapi"
125
            ],
126
            $xml);
127
        $data->setEveApiXml($xml);
128
        return $this;
129
    }
130
    /**
131
     * @param string                   $fileName
132
     * @param EveApiReadWriteInterface $data
133
     *
134
     * @return false|string
135
     * @throws \DomainException
136
     * @throws \InvalidArgumentException
137
     * @throws \LogicException
138
     */
139
    protected function performTransform($fileName, EveApiReadWriteInterface $data)
140
    {
141
        libxml_clear_errors();
142
        libxml_use_internal_errors(true);
143
        libxml_clear_errors();
144
        $xslt = $this->getXslt();
145
        $dom = $this->getDom();
146
        $dom->load($fileName);
147
        $xslt->importStylesheet($dom);
148
        $result = false;
149
        try {
150
            $result = $xslt->transformToXml(new \SimpleXMLElement($data->getEveApiXml()));
151
        } catch (\Exception $exc) {
152
            $mess = 'XML cause SimpleXMLElement exception in';
153
            $this->getYem()
154
                ->triggerLogEvent('Yapeal.log.log',
155
                    Logger::WARNING,
156
                    $this->createEveApiMessage($mess, $data),
157
                    ['exception' => $exc]);
158
        }
159
        if (false === $result) {
160
            /**
161
             * @var array $errors
162
             */
163
            $errors = libxml_get_errors();
164
            if (0 !== count($errors)) {
165
                foreach ($errors as $error) {
166
                    $this->getYem()
167
                        ->triggerLogEvent('Yapeal.Log.log', Logger::NOTICE, $error->message);
168
                }
169
            }
170
            $apiName = $data->getEveApiName();
171
            $data->setEveApiName('Untransformed_' . $apiName);
172
            // Cache error causing XML.
173
            $this->emitEvents($data, 'preserve', 'Yapeal.Xml.Error');
174
            $data->setEveApiName($apiName);
175
        }
176
        libxml_clear_errors();
177
        libxml_use_internal_errors(false);
178
        libxml_clear_errors();
179
        return $result;
180
    }
181
    /**
182
     * @return \DOMDocument
183
     */
184
    private function getDom()
185
    {
186
        if (null === $this->dom) {
187
            $this->dom = new \DOMDocument();
188
        }
189
        return $this->dom;
190
    }
191
    /**
192
     * @return \XSLTProcessor
193
     */
194
    private function getXslt()
195
    {
196
        if (null === $this->xslt) {
197
            $this->xslt = new \XSLTProcessor();
198
        }
199
        return $this->xslt;
200
    }
201
    /**
202
     * @var \DOMDocument $dom
203
     */
204
    private $dom;
205
    /**
206
     * Holds tidy config settings.
207
     *
208
     * @var array $tidyConfig
209
     */
210
    private $tidyConfig = [
211
        'indent' => true,
212
        'indent-spaces' => 4,
213
        'input-xml' => true,
214
        'newline' => 'LF',
215
        'output-xml' => true,
216
        'wrap' => '1000'
217
    ];
218
    /**
219
     * @var \XSLTProcessor $xslt
220
     */
221
    private $xslt;
222
}
223