Combiner::appendItens()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
c 0
b 0
f 0
rs 9.6666
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of gpupo/pipe2
5
 *
6
 * (c) Gilmar Pupo <[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
 * For more information, see
12
 * <https://opensource.gpupo.com/pipe2/>.
13
 */
14
15
namespace Gpupo\Pipe2\Merge\Attributes;
16
17
use Gpupo\Common\Entity\CollectionInterface;
18
use Gpupo\Pipe2\Traits\DocumentContainerTrait;
19
use Gpupo\Pipe2\Traits\ParserTrait;
20
21
class Combiner
22
{
23
    use ParserTrait;
24
    use DocumentContainerTrait;
25
26
    protected $idField;
27
28
    protected function getIdField()
29
    {
30
        return $this->idField;
31
    }
32
33
    public function __construct(Array $parameters)
34
    {
35
        $this->idField = $parameters['idField'];
36
        $firstDocument = $this->factoryCollectionFromFilePath($parameters['firstDocument']);
37
        $secondDocument = $this->factoryCollectionFromFilePath($parameters['secondDocument']);
38
        $this->setDocument(new Document($firstDocument->getMeta()), $parameters['formatOutput']);
39
        $this->appendItens($this->combine($firstDocument, $secondDocument));
40
    }
41
42
    protected function factoryCollectionFromFilePath($filePath)
43
    {
44
        $data = $this->parserFromFile($filePath);
45
46
        $collection  =  new Collection($this->parserProcess($data));
47
        $collection->setMeta($this->parserMetas($data));
48
49
        return $collection;
50
    }
51
52
    protected function hasKey($item)
53
    {
54
        if ($item instanceof CollectionInterface && $item->containsKey($this->getIdField())) {
55
            return true;
56
        }
57
58
        if (array_key_exists($this->getIdField(), $item)) {
59
            return true;
60
        }
61
        error_log('Warning:Item Field ['.$this->getIdField().'] not found. Try setup --idField options.');
62
63
        return false;
64
    }
65
66
    protected function parserProcess(Array $raw)
67
    {
68
        $list = [];
69
70
        foreach ($raw as $data) {
71
            if ($data['tag'] !== 'item') {
72
                continue;
73
            }
74
            $item = $this->parserItems($data);
75
76
            if ($this->hasKey($item)) {
77
                $list[$item[$this->getIdField()]] = new Collection($item);
78
            }
79
        }
80
81
        return $list;
82
    }
83
84
    protected function parserMetas(Array $raw)
85
    {
86
        $list = [];
87
88
        foreach ($raw as $data) {
89
            if ($data['tag'] === 'item') {
90
                continue;
91
            }
92
            if (array_key_exists('attributes', $data)) {
93
                $list[$data['tag']] = $data['attributes'];
94
            } elseif (array_key_exists('value', $data)) {
95
                $list[$data['tag']] = $data['value'];
96
            }
97
        }
98
99
        return $list;
100
    }
101
102
    protected function combine(CollectionInterface $first, CollectionInterface $second)
103
    {
104
        foreach ($first as $item) {
0 ignored issues
show
Bug introduced by
The expression $first of type object<Gpupo\Common\Entity\CollectionInterface> is not traversable.
Loading history...
105
            if (!$this->hasKey($item)) {
106
                continue;
107
            }
108
            $key =  $item->get($this->idField);
109
110
            if ($second->containsKey($key)) {
111
                foreach ($second->get($key) as $field => $value) {
112
                    if (!$item->containsKey($field)) {
113
                        $item->set($field, $value);
114
                    }
115
                }
116
            }
117
        }
118
119
        return $first;
120
    }
121
122
    protected function appendItens($list)
123
    {
124
        foreach ($list as $item) {
125
            $itemElement = $this->document->createElement('item');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Gpupo\Pipe2\DocumentInterface as the method createElement() does only exist in the following implementations of said interface: Gpupo\Pipe2\Converter\Document, Gpupo\Pipe2\DocumentAbstract, Gpupo\Pipe2\Merge\Attributes\Document.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
126
            $id = $item->get($this->getIdField());
127
            $itemElement->setAttribute('id', $id);
128
            $this->populateDocument($itemElement, $item);
129
        }
130
    }
131
}
132