Completed
Push — master ( 659b14...17b09c )
by Tobias
07:00
created

XliffLoader::getXmlErrors()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 15
cts 15
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 13
nc 2
nop 1
crap 4
1
<?php
2
3
/*
4
 * This file is part of the PHP Translation package.
5
 *
6
 * (c) PHP Translation team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Translation\SymfonyStorage\Loader;
13
14
use Nyholm\NSA;
15
use Symfony\Component\Translation\Loader\XliffFileLoader;
16
use Symfony\Component\Translation\MessageCatalogue;
17
use Symfony\Component\Translation\Exception\InvalidResourceException;
18
19
/**
20
 * This class is an ugly hack to allow loading Xliff from string content.
21
 *
22
 * @author Tobias Nyholm <[email protected]>
23
 */
24
class XliffLoader extends XliffFileLoader
25
{
26
    /**
27
     * @param string           $content   xml content
28
     * @param MessageCatalogue $catalogue
29
     * @param string           $domain
30
     */
31 5
    public function extractFromContent($content, MessageCatalogue $catalogue, $domain)
32
    {
33
        try {
34 5
            $dom = $this->loadFileContent($content);
35 5
        } catch (\InvalidArgumentException $e) {
36 2
            throw new InvalidResourceException(sprintf('Unable to load data: %s', $e->getMessage()), $e->getCode(), $e);
37
        }
38
39 3
        if (!method_exists($this, 'getVersionNumber')) {
40
            // Symfony 2.7
41
            throw new \RuntimeException('Cannot use XliffLoader::extractFromContent with Symfony 2.7');
42
        }
43
44 3
        $xliffVersion = NSA::invokeMethod($this, 'getVersionNumber', $dom);
45 3
        NSA::invokeMethod($this, 'validateSchema', $xliffVersion, $dom, NSA::invokeMethod($this, 'getSchema', $xliffVersion));
46
47 3
        if ('1.2' === $xliffVersion) {
48 2
            NSA::invokeMethod($this, 'extractXliff1', $dom, $catalogue, $domain);
49 2
        }
50
51 3
        if ('2.0' === $xliffVersion) {
52 1
            NSA::invokeMethod($this, 'extractXliff2', $dom, $catalogue, $domain);
53 1
        }
54 3
    }
55
56
    /**
57
     * Loads an XML file.
58
     *
59
     * Taken and modified from Symfony\Component\Config\Util\XmlUtils
60
     *
61
     * @author Fabien Potencier <[email protected]>
62
     * @author Martin Hasoň <[email protected]>
63
     *
64
     * @param string $content An XML file path
65
     *
66
     * @return \DOMDocument
67
     *
68
     * @throws \InvalidArgumentException When loading of XML file returns error
69
     */
70 5
    private function loadFileContent($content)
71
    {
72 5
        if ('' === trim($content)) {
73 1
            throw new \InvalidArgumentException('Content does not contain valid XML, it is empty.');
74
        }
75
76 4
        $internalErrors = libxml_use_internal_errors(true);
77 4
        $disableEntities = libxml_disable_entity_loader(true);
78 4
        libxml_clear_errors();
79
80 4
        $dom = new \DOMDocument();
81 4
        $dom->validateOnParse = true;
82 4
        if (!$dom->loadXML($content, LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
83 1
            libxml_disable_entity_loader($disableEntities);
84
85 1
            throw new \InvalidArgumentException(implode("\n", static::getXmlErrors($internalErrors)));
0 ignored issues
show
Bug introduced by
Since getXmlErrors() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of getXmlErrors() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
86
        }
87
88 3
        $dom->normalizeDocument();
89
90 3
        libxml_use_internal_errors($internalErrors);
91 3
        libxml_disable_entity_loader($disableEntities);
92
93 3
        foreach ($dom->childNodes as $child) {
94 3
            if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
95
                throw new \InvalidArgumentException('Document types are not allowed.');
96
            }
97 3
        }
98
99 3
        libxml_clear_errors();
100 3
        libxml_use_internal_errors($internalErrors);
101
102 3
        return $dom;
103
    }
104
105 1
    private function getXmlErrors($internalErrors)
0 ignored issues
show
Bug introduced by
Consider using a different method name as you override a private method of the parent class.

Overwriting private methods is generally fine as long as you also use private visibility. It might still be preferable for understandability to use a different method name.

Loading history...
106
    {
107 1
        $errors = [];
108 1
        foreach (libxml_get_errors() as $error) {
109 1
            $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
110 1
                LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
111 1
                $error->code,
112 1
                trim($error->message),
113 1
                $error->file ?: 'n/a',
114 1
                $error->line,
115 1
                $error->column
116 1
            );
117 1
        }
118
119 1
        libxml_clear_errors();
120 1
        libxml_use_internal_errors($internalErrors);
121
122 1
        return $errors;
123
    }
124
}
125