Completed
Push — master ( d14e53...2de3b1 )
by Nikola
04:53
created

AbstractSaxHandler::process()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4.074

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 5
cts 6
cp 0.8333
rs 9.2
c 0
b 0
f 0
cc 4
eloc 6
nc 6
nop 2
crap 4.074
1
<?php
2
/*
3
 * This file is part of the runopencode/sax, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\Sax\Handler;
11
12
use Psr\Http\Message\StreamInterface;
13
use RunOpenCode\Sax\Contract\SaxHandlerInterface;
14
use RunOpenCode\Sax\Exception\ParseException;
15
16
/**
17
 * Class AbstractSaxHandler
18
 *
19
 * Sax handler prototype.
20
 *
21
 * @package RunOpenCode\Sax
22
 */
23
abstract class AbstractSaxHandler implements SaxHandlerInterface
24
{
25
    /**
26
     * @var array
27
     */
28
    protected $options;
29
30
    /**
31
     * AbstractSaxHandler constructor.
32
     *
33
     * @param array $options
34
     */
35 5
    public function __construct(array $options = array())
36
    {
37 5
        $this->options = array_merge(array(
38 5
            'buffer_size' => 4096,
39 5
        ), $options);
40 5
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45 5
    final public function parse(StreamInterface $stream)
46
    {
47 5
        $parser = xml_parser_create();
48
49 5
        $this->onDocumentStart($parser, $stream);
50
51 5
        $this->attachHandlers($parser);
52
53 5
        $this->process($parser, $stream);
54
55 4
        $this->onDocumentEnd($parser, $stream);
56
57 4
        xml_parser_free($parser);
58
59 4
        $stream->close();
60
61 4
        return $this->getResult();
62
    }
63
64
    /**
65
     * Document start handler, executed when parsing process started.
66
     *
67
     * @param resource $parser Parser handler.
68
     * @param StreamInterface $stream XML stream.
69
     */
70
    abstract protected function onDocumentStart($parser, $stream);
71
72
    /**
73
     * Element start handler, executed when XML tag is entered.
74
     *
75
     * @param resource $parser Parser handler.
76
     * @param string $name Tag name.
77
     * @param array $attributes Element attributes.
78
     */
79
    abstract protected function onElementStart($parser, $name, $attributes);
80
81
    /**
82
     * Element CDATA handler, executed when XML tag CDATA is parsed.
83
     *
84
     * @param resource $parser Parser handler.
85
     * @param string $data Element CDATA.
86
     */
87
    abstract protected function onElementData($parser, $data);
88
89
    /**
90
     * Element end handler, executed when XML tag is leaved.
91
     *
92
     * @param resource $parser Parser handler.
93
     * @param string $name Tag name.
94
     */
95
    abstract protected function onElementEnd($parser, $name);
96
97
    /**
98
     * Document end handler, executed when parsing process ended.
99
     *
100
     * @param resource $parser Parser handler.
101
     * @param StreamInterface $stream XML stream.
102
     */
103
    abstract protected function onDocumentEnd($parser, $stream);
104
105
    /**
106
     * Parsing error handler.
107
     *
108
     * @param string $message Parsing error message.
109
     * @param int $code Error code.
110
     * @param int $lineno XML line number which caused error.
111
     */
112
    abstract protected function onParseError($message, $code, $lineno);
113
114
    /**
115
     * Get parsing result.
116
     *
117
     * Considering that your handler processed XML document, this method will collect
118
     * parsing result. This method is called last and it will provide parsing result to invoker.
119
     *
120
     * @return mixed Parsing result
121
     */
122
    abstract protected function getResult();
123
124
    /**
125
     * Parse path to XML document/string content.
126
     *
127
     * @param resource $parser Parser.
128
     * @param StreamInterface $stream XML document stream.
129
     * @return AbstractSaxHandler $this Fluent interface.
130
     *
131
     * @throws \RuntimeException
132
     */
133 5
    private function process($parser, StreamInterface $stream)
134
    {
135 5
        if ($stream->eof()) {
136
            $stream->rewind();
137
        }
138
139 5
        while ($data = $stream->read($this->options['buffer_size'])) {
140 4
            xml_parse($parser, $data, $stream->eof()) || $this->onParseError(xml_error_string(xml_get_error_code($parser)), xml_get_error_code($parser), xml_get_current_line_number($parser));
141
        }
142
143 4
        return $this;
144
    }
145
146
    /**
147
     * Attach handlers.
148
     *
149
     * @param resource $parser XML parser.
150
     * @return AbstractSaxHandler $this Fluent interface.
151
     */
152 5
    private function attachHandlers($parser)
153
    {
154 5
        xml_set_element_handler(
155
            $parser,
156
            \Closure::bind(function ($parser, $name, $attributes) {
157 4
                $this->onElementStart($parser, $name, $attributes);
158 5
            }, $this),
159
            \Closure::bind(function ($parser, $name) {
160 4
                $this->onElementEnd($parser, $name);
161 5
            }, $this)
162
        );
163
164 5
        xml_set_character_data_handler(
165
            $parser,
166 5
            \Closure::bind(function ($parser, $data) {
167 4
                $this->onElementData($parser, $data);
168 5
            }, $this));
169
170 5
        return $this;
171
    }
172
}
173