ChildTrait::getChildById()   A
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 15
cts 15
cp 1
rs 9.0111
c 0
b 0
f 0
cc 6
nc 6
nop 1
crap 6
1
<?php
2
namespace nstdio\svg\traits;
3
4
5
use nstdio\svg\container\ContainerInterface;
6
use nstdio\svg\ElementInterface;
7
use nstdio\svg\ElementStorage;
8
use nstdio\svg\SVGElement;
9
use nstdio\svg\XMLDocumentInterface;
10
11
/**
12
 * Class ChildTrait
13
 *
14
 * @package nstdio\svg\traits
15
 * @author  Edgar Asatryan <[email protected]>
16
 */
17
trait ChildTrait
18
{
19
    /**
20
     * @var ElementStorage
21
     */
22
    protected $child;
23
24
    /**
25
     * @param string $name
26
     *
27
     * @return ContainerInterface[]
28
     */
29 8
    public function getChild($name)
30
    {
31 8
        $find = [];
32
        /** @var ContainerInterface $item */
33 8
        foreach ($this->child as $item) {
34 8
            if (strtolower($item->getName()) === strtolower($name)) {
35 8
                $find[] = $item;
36 8
            }
37 8
            if ($item->hasChild()) {
38 4
                $find = array_merge($find, $item->getChild($name));
39 4
            }
40 8
        }
41
42 8
        return $find;
43
    }
44
45
    /**
46
     * @param $id
47
     *
48
     * @return ContainerInterface
49
     */
50 4
    public function getChildById($id)
51
    {
52 4
        $find = null;
53
        /** @var ContainerInterface|SVGElement $item */
54 4
        foreach ($this->child as $item) {
55 3
            if ($item->id === $id) {
56 3
                $find = $item;
57 3
            }
58 4
        }
59 4
        if ($find === null) {
60 4
            foreach ($this->child as $item) {
61 3
                if ($item->hasChild()) {
62 3
                    $find = $item->getChildById($id);
63 3
                }
64 4
            }
65 4
        }
66
67 4
        return $find;
68
    }
69
70
    /**
71
     * @return ContainerInterface|null
72
     */
73 66
    public function getFirstChild()
74
    {
75 66
        if (!$this->hasChild()) {
76 1
            return null;
77
        }
78
79 66
        return $this->child[0];
80
    }
81
82
    /**
83
     * @return bool
84
     */
85 66
    public function hasChild()
86
    {
87 66
        return count($this->child) > 0;
88
    }
89
90
    /**
91
     * @return ContainerInterface[]|ElementStorage
92
     */
93 2
    public function getChildren()
94
    {
95 2
        return $this->child;
96
    }
97
98
    /**
99
     * @param $index
100
     *
101
     * @return ContainerInterface|SVGElement|null
102
     */
103 9
    public function getChildAtIndex($index)
104
    {
105 9
        return $this->child[$index];
106
    }
107
108
    /**
109
     * @param ElementInterface $child
110
     */
111 11
    public function removeChild(ElementInterface $child)
112
    {
113 11
        $this->child->remove($child);
114
        /** @var XMLDocumentInterface $element */
115 11
        $element = $this->getElement();
0 ignored issues
show
Bug introduced by
It seems like getElement() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
116 11
        if ($element instanceof \DOMNode) {
117 3
            $element->removeChild($child->getElement()->getElement());
0 ignored issues
show
Bug introduced by
The method getElement does only exist in nstdio\svg\XMLDocumentIn...iner\ContainerInterface, but not in DOMElement.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
118 3
        } else {
119 9
            $element->removeNode($child->getElement());
0 ignored issues
show
Bug introduced by
It seems like $child->getElement() targeting nstdio\svg\ElementInterface::getElement() can also be of type object<DOMElement> or object<nstdio\svg\container\ContainerInterface>; however, nstdio\svg\XMLDocumentInterface::removeNode() does only seem to accept object<nstdio\svg\XMLDocumentInterface>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
120
        }
121
    }
122
}