Completed
Push — issue/60 ( 77529b...558c8f )
by Alex
02:56
created

Parser::parseNode()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 3
crap 3
1
<?php
2
/*
3
 * This file is part of the feed-io package.
4
 *
5
 * (c) Alexandre Debril <[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 FeedIo;
12
13
use DOMDocument;
14
use FeedIo\Feed\ItemInterface;
15
use FeedIo\Feed\NodeInterface;
16
use FeedIo\Parser\MissingFieldsException;
17
use FeedIo\Parser\UnsupportedFormatException;
18
use Psr\Log\LoggerInterface;
19
20
/**
21
 * Parses a DOM document if its format matches the parser's standard
22
 *
23
 * Depends on :
24
 *  - FeedIo\StandardAbstract
25
 *  - Psr\Log\LoggerInterface
26
 *
27
 */
28
class Parser
29
{
30
31
    /**
32
     * @var \Psr\Log\LoggerInterface
33
     */
34
    protected $logger;
35
36
    /**
37
     * @var array[FilterInterface]
38
     */
39
    protected $filters = array();
40
41
    /**
42
     * @var StandardAbstract
43
     */
44
    protected $standard;
45
46
    /**
47
     * @param StandardAbstract $standard
48
     * @param LoggerInterface  $logger
49
     */
50 32
    public function __construct(StandardAbstract $standard, LoggerInterface $logger)
51
    {
52 32
        $this->standard = $standard;
53 32
        $this->logger = $logger;
54 32
    }
55
56
    /**
57
     * @return StandardAbstract
58
     */
59 20
    public function getStandard()
60
    {
61 20
        return $this->standard;
62
    }
63
64
    /**
65
     * @param $tagName
66
     * @return bool
67
     */
68 7
    public function isItem($tagName)
69
    {
70 7
        return (strtolower($this->standard->getItemNodeName()) === strtolower($tagName));
71
    }
72
73
    /**
74
     * @param  FilterInterface $filter
75
     * @return $this
76
     */
77 3
    public function addFilter(FilterInterface $filter)
78
    {
79 3
        $this->filters[] = $filter;
80
81 3
        return $this;
82
    }
83
84
    /**
85
     * @param  DOMDocument                       $document
86
     * @param  FeedInterface                     $feed
87
     * @return \FeedIo\FeedInterface
88
     * @throws Parser\MissingFieldsException
89
     * @throws Parser\UnsupportedFormatException
90
     */
91 8
    public function parse(DOMDocument $document, FeedInterface $feed)
92
    {
93 8
        if (!$this->standard->canHandle($document)) {
94 1
            throw new UnsupportedFormatException('this is not a supported format');
95
        }
96
97 7
        $this->checkBodyStructure($document, $this->standard->getMandatoryFields());
98 7
        $element = $this->standard->getMainElement($document);
99
100 7
        $this->parseNode($feed, $element, $this->standard->getFeedRuleSet());
101
102 7
        return $feed;
103
    }
104
105
    /**
106
     * @param  DOMDocument            $document
107
     * @param  array                  $mandatoryFields
108
     * @return $this
109
     * @throws MissingFieldsException
110
     */
111 9
    public function checkBodyStructure(DOMDocument $document, array $mandatoryFields)
112
    {
113 9
        $errors = array();
114
115 9
        $element = $document->documentElement;
116 9
        foreach ($mandatoryFields as $field) {
117 2
            $list = $element->getElementsByTagName($field);
118 2
            if (0 === $list->length) {
119 2
                $errors[] = $field;
120
            }
121
        }
122
123 9
        if (!empty($errors)) {
124 1
            $message = "missing mandatory field(s) : ".implode(',', $errors);
125 1
            $this->logger->warning($message);
126 1
            throw new MissingFieldsException($message);
127
        }
128
129 8
        return $this;
130
    }
131
132
    /**
133
     * @param  NodeInterface $item
134
     * @param  \DOMElement   $element
135
     * @param  RuleSet       $ruleSet
136
     * @return NodeInterface
137
     */
138 8
    public function parseNode(NodeInterface $item, \DOMElement $element, RuleSet $ruleSet)
139
    {
140 8
        foreach ($element->childNodes as $node) {
141 7
            if ($node instanceof \DOMElement) {
142 7
                $this->handleNode($item, $node, $ruleSet);
143
            }
144
        }
145
146 8
        return $item;
147
    }
148
149
    /**
150
     * @param NodeInterface $item
151
     * @param \DOMElement $node
152
     * @param RuleSet $ruleSet
153
     * @return $this
154
     */
155 7
    protected function handleNode(NodeInterface $item, \DOMElement $node, RuleSet $ruleSet)
156
    {
157 7
        if ($this->isItem($node->tagName) && $item instanceof FeedInterface) {
158 6
            $newItem = $this->parseNode($item->newItem(), $node, $this->standard->getItemRuleSet());
159 6
            $this->addValidItem($item, $newItem);
160
        } else {
161 7
            $rule = $ruleSet->get($node->tagName);
162 7
            $rule->setProperty($item, $node);
163
        }
164
165 7
        return $this;
166
    }
167
168
    /**
169
     * @param  FeedInterface $feed
170
     * @param  NodeInterface $item
171
     * @return $this
172
     */
173 6
    public function addValidItem(FeedInterface $feed, NodeInterface $item)
174
    {
175 6
        if ($item instanceof ItemInterface && $this->isValid($item)) {
176 6
            $feed->add($item);
177
        }
178
179 6
        return $this;
180
    }
181
182
    /**
183
     * @param  ItemInterface $item
184
     * @return bool
185
     */
186 8
    public function isValid(ItemInterface $item)
187
    {
188 8
        foreach ($this->filters as $filter) {
189 2
            if (!$filter->isValid($item)) {
190 2
                return false;
191
            }
192
        }
193
194 7
        return true;
195
    }
196
}
197