Completed
Push — master ( ac95bd...c505ae )
by Nikola
02:57
created

AbstractSaxHandler::attachHandlers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

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