Completed
Pull Request — master (#19)
by Auke
01:42
created

Proxy::getElementById()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/*
3
 * This file is part of the Ariadne Component Library.
4
 *
5
 * (c) Muze <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace arc\xml;
12
13
/**
14
 * This class is a proxy for both the SimpleXMLElement and DOMElement 
15
 * properties and methods.
16
 * @property \SimpleXMLElement nodeValue
17
 */
18
class Proxy extends \ArrayObject implements DOMElement, SimpleXMLElement {
19
20
    use \arc\traits\Proxy {
21
        \arc\traits\Proxy::__construct as private ProxyConstruct;
22
        \arc\traits\Proxy::__call as private ProxyCall;
23
    }
24
25
    private $parser = null;
26
27 6
    public function __construct( $node, $parser) {
28 6
        $this->ProxyConstruct( $node );
29 6
        $this->parser = $parser;
30 6
    }
31
32 1
    public function __toString() {
33 1
        return $this->target->asXML();
34
    }
35
36 2
    private function _isDomProperty( $name ) {
37
        $domProperties = [
38 2
            'tagName', 'nodeType', 'parentNode', 
39 2
            'firstChild', 'lastChild', 'previousSibling', 'nextSibling',
40 2
            'ownerDocument', 'namespaceURI', 'prefix', 
41 2
            'localName', 'baseURI', 'textContent'
42 2
        ];
43 2
        return in_array( $name, $domProperties );
44
    }
45
46 2
    private function _getTargetProperty($name) {
47 2
        $value = null;
48 2
        if ( !$this->_isDomProperty($name) ) {
49 2
            $value = $this->target->{$name};
50 2
        } else {
51 1
            $dom = dom_import_simplexml($this->target);
52 1
            if ( isset($dom) ) {
53 1
                $value = $dom->{$name};
54 1
            }
55
        }
56 2
        return $value;
57
    }
58
59 2
    private function _proxyResult( $value ) {
60 2
        if ( $value instanceof \DOMElement ) {
61
            $value = simplexml_import_dom($value);
62
        }
63 2
        if ( $value instanceof \SimpleXMLElement ) {
64 2
            return new static( $value, $this->parser );
65
        } else {
66 1
            return $value;
67
        }
68
    }
69
70 5
    public function __get( $name) {
71 5
        if ($name == 'nodeValue') {
72 5
            return $this->target;
73
        }
74 2
        return $this->_proxyResult( $this->_getTargetProperty($name) );
75
    }
76
    
77 2
    private function _domCall( $name, $args ) {
78 2
        $dom = dom_import_simplexml($this->target);
79 2
        foreach ( $args as $index => $arg ) {
80 2
            if ( $arg instanceof \arc\xml\Proxy ) {
81 1
                $args[$index] = dom_import_simplexml( $arg->nodeValue );
82 2
            } else if ( $arg instanceof \SimpleXMLElement ) {
83
                $args[$index] = dom_import_simplexml( $arg );
84
            }
85 2
        }
86
        $importMethods = [
87 2
            'appendChild', 'insertBefore', 'replaceChild'
88 2
        ];
89 2
        if ( in_array( $name, $importMethods ) ) {
90 1
            if ( isset($args[0]) && $args[0] instanceof \DOMNode ) {
91 1
                if ( $args[0]->ownerDocument !== $this->ownerDocument ) {
0 ignored issues
show
Documentation introduced by
The property ownerDocument 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...
92 1
                    $args[0] = $this->ownerDocument->importNode( $args[0], true);
0 ignored issues
show
Documentation introduced by
The property ownerDocument 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...
93 1
                }
94 1
            }
95 1
        }
96 2
        $result = call_user_func_array( [ $dom, $name], $args );
97 2
        if ( isset($result) && is_object($result) ) {
98 1
            if ( $result instanceof \DOMElement ) {
99 1
                return new static( $result, $this->parser );
100
            }
101
            if ( $result instanceof \DOMNodeList ) {
102
                $resultArray = [];
103
                for ( $i=0, $l=$result->length; $i<$l; $i ++ ) {
104
                    $resultArray[$i] = new static( simplexml_import_dom($result->item($i)), $this->parser );
105
                }
106
                return $resultArray;
107
            }
108
        }
109 1
        return $result;
110
    }
111
112 2
    public function __call( $name, $args ) {
113 2
        if ( !method_exists($this->target, $name) ) {
114 2
            return $this->_domCall( $name, $args );
115
        } else {
116 2
            return $this->ProxyCall($name, $args);
117
        }
118
    }
119
120
    /**
121
     * Search through the XML DOM with a single CSS selector
122
     * @param string $query the CSS selector, most CSS 2 selectors work
123
     * @return Proxy
124
     */
125 3
    public function find( $query) {
126 3
        $xpath = \arc\xml::css2Xpath( $query );
127 3
        $temp = $this->target->xpath( $xpath );
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...
128 3
        foreach ($temp as $key => $value) {
129 3
            $temp[ $key ] = new static( $value, $this->parser );
130 3
        }
131 3
        return $temp;
132
    }
133
134
    /**
135
     * Ssearches through the subtree for an element with the given id and returns it
136
     * @param string $id
137
     * @return Proxy
138
     */
139 1
    public function getElementById( $id ) {
140 1
        return current($this->find('#'.$id));
141
    }
142
    
143 2
    public function offsetGet( $offset )
144
    {
145 2
        return (string) $this->target[$offset];
146
    }
147
    
148 1
    public function offsetSet( $offset, $value )
149
    {
150 1
        $this->target[$offset] = $value;
151 1
    }
152
    
153
    public function offsetUnset( $offset )
154
    {
155
        unset( $this->target[$offset] );
156
    }
157
}
158