Completed
Push — master ( 1b3e01...ba7d86 )
by Nikola
07:03
created

AbstractSaxHandler::onDocumentStart()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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