Completed
Pull Request — master (#12)
by Auke
34:04
created

Parser::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.4746

Importance

Changes 4
Bugs 1 Features 2
Metric Value
c 4
b 1
f 2
dl 0
loc 9
ccs 5
cts 8
cp 0.625
rs 9.6666
cc 3
eloc 5
nc 3
nop 1
crap 3.4746
1
<?php
2
3
namespace arc\xml;
4
5
class Parser
6
{
7
8
    public $namespaces = array();
9
10 3
    public function __construct( $options = array() )
11
    {
12 3
        $optionList = array( 'namespaces' );
13 3
        foreach( $options as $option => $optionValue) {
14
            if (in_array( $option, $optionList )) {
15
                $this->{$option} = $optionValue;
16
            }
17 3
        }
18 3
    }
19
20 3
    public function parse( $xml, $encoding = null )
21
    {
22 3
        if (!$xml) {
23
            return Proxy( null );
24
        }
25 3
        if ($xml instanceof Proxy) { // already parsed
26
            return $xml;
27
        }
28 3
        $xml = (string) $xml;
29
        try {
30 3
            return $this->parseFull( $xml, $encoding );
31 1
        } catch( \arc\Exception $e) {
32 1
            return $this->parsePartial( $xml, $encoding );
33
        }
34
    }
35
36 1
    private function parsePartial( $xml, $encoding )
37
    {
38
        // add a known (single) root element with all declared namespaces
39
        // libxml will barf on multiple root elements
40
        // and it will silently drop namespace prefixes not defined in the document
41 1
        $root = '<arcxmlroot';
42 1
        foreach ($this->namespaces as $name => $uri) {
43
            if ($name === 0) {
44
                $root .= ' xmlns="';
45
            } else {
46
                $root .= ' xmlns:'.$name.'="';
47
            }
48
            $root .= htmlspecialchars( $uri ) . '"';
49 1
        }
50 1
        $root .= '>';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
51 1
        $result = $this->parseFull( $root.$xml.'</arcxmlroot>', $encoding );
52
        $result = $result->firstChild->childNodes;
0 ignored issues
show
Documentation introduced by
The property firstChild does not exist on object<arc\xml\Proxy>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
53
        return $result;
54
    }
55
56 3
    private function parseFull( $xml, $encoding = null )
57
    {
58 3
        $dom = new \DomDocument();
59 3
        if ($encoding) {
60
            $xml = '<?xml encoding="' . $encoding . '">' . $xml;
61
        }
62 3
        libxml_disable_entity_loader(); // prevents XXE attacks
63 3
        $prevErrorSetting = libxml_use_internal_errors(true);
64 3
        if ($dom->loadXML( $xml )) {
65 3
            if ($encoding) {
66
                foreach( $dom->childNodes as $item) {
67
                    if ($item->nodeType == XML_PI_NODE) {
68
                        $dom->removeChild( $item );
69
                        break;
70
                    }
71
                }
72
                $dom->encoding = $encoding;
73
            }
74 3
	        libxml_use_internal_errors( $prevErrorSetting );
75 3
            return new Proxy( simplexml_import_dom( $dom ), $this );
76
        }
77 1
        $errors = libxml_get_errors();
78 1
        libxml_clear_errors();
79 1
        libxml_use_internal_errors( $prevErrorSetting );
80 1
        $message = 'Incorrect xml passed.';
81 1
        foreach ($errors as $error) {
82 1
            $message .= '\nline: '.$error->line.'; column: '.$error->column.'; '.$error->message;
83 1
        }
84 1
        throw new \arc\Exception( $message, \arc\exceptions::ILLEGAL_ARGUMENT );
85
    }
86
}
87