Completed
Push — issue/29 ( ed3ccc )
by Alex
02:58
created

Parser::checkBodyStructure()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 20
ccs 7
cts 14
cp 0.5
rs 9.2
cc 4
eloc 12
nc 6
nop 2
crap 6
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 26
    public function __construct(StandardAbstract $standard, LoggerInterface $logger)
51
    {
52 26
        $this->standard = $standard;
53 26
        $this->logger = $logger;
54 26
    }
55
56
    /**
57
     * @return StandardAbstract
58
     */
59 21
    public function getStandard()
60
    {
61 21
        return $this->standard;
62
    }
63
64
    /**
65
     * @param $tagName
66
     * @return bool
67
     */
68 6
    public function isItem($tagName)
69
    {
70 6
        return (strtolower($this->standard->getItemNodeName()) === strtolower($tagName));
71
    }
72
73
    /**
74
     * @param  FilterInterface $filter
75
     * @return $this
76
     */
77 7
    public function addFilter(FilterInterface $filter)
78
    {
79 7
        $this->filters[] = $filter;
80
81 7
        return $this;
82
    }
83
84
    /**
85
     * @return $this
86
     */
87 6
    public function initFilters(FeedInterface $feed)
88
    {
89 6
        foreach ($this->filters as $filter) {
90
            $filter->init($feed);
91 6
        }
92
93 6
        return $this;
94
    }
95
96
    /**
97
     * @param  DOMDocument                       $document
98
     * @param  FeedInterface                     $feed
99
     * @return \FeedIo\FeedInterface
100
     * @throws Parser\MissingFieldsException
101
     * @throws Parser\UnsupportedFormatException
102
     */
103 6
    public function parse(DOMDocument $document, FeedInterface $feed)
104
    {
105 6
        if (!$this->standard->canHandle($document)) {
106
            throw new UnsupportedFormatException('this is not a supported format');
107
        }
108
109 6
        $this->initFilters($feed);
110 6
        $this->checkBodyStructure($document, $this->standard->getMandatoryFields());
111 6
        $element = $this->standard->getMainElement($document);
112
113 6
        $this->parseNode($feed, $element, $this->standard->getFeedRuleSet());
114
115 6
        return $feed;
116
    }
117
118
    /**
119
     * @param  DOMDocument            $document
120
     * @param  array                  $mandatoryFields
121
     * @return $this
122
     * @throws MissingFieldsException
123
     */
124 6
    public function checkBodyStructure(DOMDocument $document, array $mandatoryFields)
125
    {
126 6
        $errors = array();
127
128 6
        $element = $document->documentElement;
129 6
        foreach ($mandatoryFields as $field) {
130
            $list = $element->getElementsByTagName($field);
131
            if (0 === $list->length) {
132
                $errors[] = $field;
133
            }
134 6
        }
135
136 6
        if (!empty($errors)) {
137
            $message = "missing mandatory field(s) : ".implode(',', $errors);
138
            $this->logger->warning($message);
139
            throw new MissingFieldsException($message);
140
        }
141
142 6
        return $this;
143
    }
144
145
    /**
146
     * @param  NodeInterface $item
147
     * @param  \DOMElement   $element
148
     * @param  RuleSet       $ruleSet
149
     * @return NodeInterface
150
     */
151 6
    public function parseNode(NodeInterface $item, \DOMElement $element, RuleSet $ruleSet)
152
    {
153 6
        foreach ($element->childNodes as $node) {
154 6
            if ($node instanceof \DOMElement) {
155 6
                if ($this->isItem($node->tagName) && $item instanceof FeedInterface) {
156 6
                    $newItem = $this->parseNode($item->newItem(), $node, $this->standard->getItemRuleSet());
157 6
                    $this->addValidItem($item, $newItem);
158 6
                } else {
159 6
                    $rule = $ruleSet->get($node->tagName);
160 6
                    $rule->setProperty($item, $node);
161
                }
162 6
            }
163 6
        }
164
165 6
        return $item;
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 6
        }
178
179 6
        return $this;
180
    }
181
182
    /**
183
     * @param  ItemInterface $item
184
     * @return bool
185
     */
186 6
    public function isValid(ItemInterface $item)
187
    {
188 6
        foreach ($this->filters as $filter) {
189
            if (!$filter->isValid($item)) {
190
                return false;
191
            }
192 6
        }
193
194 6
        return true;
195
    }
196
}
197