Dom   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 220
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 11
Bugs 0 Features 0
Metric Value
eloc 48
c 11
b 0
f 0
dl 0
loc 220
ccs 53
cts 53
cp 1
rs 10
wmc 19

11 Methods

Rating   Name   Duplication   Size   Complexity  
A loadFromFile() 0 8 2
A __toString() 0 5 1
A __construct() 0 11 3
A find() 0 5 1
A getElementsByClass() 0 5 1
A getElementById() 0 5 1
A isLoaded() 0 4 2
A loadStr() 0 18 3
A setOptions() 0 5 1
A getElementsByTag() 0 5 1
A loadFromUrl() 0 13 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPHtmlParser;
6
7
use GuzzleHttp\Psr7\Request;
8
use GuzzleHttp\Client;
9
use PHPHtmlParser\Contracts\Dom\CleanerInterface;
10
use PHPHtmlParser\Contracts\Dom\ParserInterface;
11
use PHPHtmlParser\Contracts\DomInterface;
12
use PHPHtmlParser\Discovery\CleanerDiscovery;
13
use PHPHtmlParser\Discovery\DomParserDiscovery;
14
use PHPHtmlParser\Dom\Node\Collection;
15
use PHPHtmlParser\Dom\RootAccessTrait;
16
use PHPHtmlParser\Exceptions\ChildNotFoundException;
17
use PHPHtmlParser\Exceptions\CircularException;
18
use PHPHtmlParser\Exceptions\LogicalException;
19
use PHPHtmlParser\Exceptions\NotLoadedException;
20
use PHPHtmlParser\Exceptions\StrictException;
21
use PHPHtmlParser\Exceptions\UnknownChildTypeException;
22
use Psr\Http\Client\ClientExceptionInterface;
23
use Psr\Http\Client\ClientInterface;
24
use Psr\Http\Message\RequestInterface;
25
26
/**
27
 * Class Dom.
28
 */
29
class Dom implements DomInterface
30
{
31
    use RootAccessTrait;
32
33
    /**
34
     * The charset we would like the output to be in.
35
     *
36
     * @var string
37
     */
38
    private $defaultCharset = 'UTF-8';
39
40
    /**
41
     * The document string.
42
     *
43
     * @var Content
44
     */
45
    private $content;
46
47
    /**
48
     * A global options array to be used by all load calls.
49
     *
50
     * @var ?Options
51
     */
52
    private $globalOptions;
53
54
    /**
55
     * @var ParserInterface
56
     */
57
    private $domParser;
58
    /**
59
     * @var CleanerInterface
60
     */
61
    private $domCleaner;
62
63 303
    public function __construct(?ParserInterface $domParser = null, ?CleanerInterface $domCleaner = null)
64
    {
65 303
        if ($domParser === null) {
66 303
            $domParser = DomParserDiscovery::find();
67
        }
68 303
        if ($domCleaner === null) {
69 303
            $domCleaner = CleanerDiscovery::find();
70
        }
71
72 303
        $this->domParser = $domParser;
73 303
        $this->domCleaner = $domCleaner;
74 303
    }
75
76
    /**
77
     * Returns the inner html of the root node.
78
     *
79
     * @throws ChildNotFoundException
80
     * @throws UnknownChildTypeException
81
     * @throws NotLoadedException
82
     */
83 24
    public function __toString(): string
84
    {
85 24
        $this->isLoaded();
86
87 24
        return $this->root->innerHtml();
88
    }
89
90
    /**
91
     * Loads the dom from a document file/url.
92
     *
93
     * @throws ChildNotFoundException
94
     * @throws CircularException
95
     * @throws Exceptions\ContentLengthException
96
     * @throws LogicalException
97
     * @throws StrictException
98
     */
99 57
    public function loadFromFile(string $file, ?Options $options = null): Dom
100
    {
101 57
        $content = @\file_get_contents($file);
102 57
        if ($content === false) {
103 3
            throw new LogicalException('file_get_contents failed and returned false when trying to read "' . $file . '".');
104
        }
105
106 54
        return $this->loadStr($content, $options);
107
    }
108
109
    /**
110
     * Use a curl interface implementation to attempt to load
111
     * the content from a url.
112
     *
113
     * @throws ChildNotFoundException
114
     * @throws CircularException
115
     * @throws Exceptions\ContentLengthException
116
     * @throws LogicalException
117
     * @throws StrictException
118
     * @throws ClientExceptionInterface
119
     */
120 9
    public function loadFromUrl(string $url, ?Options $options = null, ?ClientInterface $client = null, ?RequestInterface $request = null): Dom
121
    {
122 9
        if ($client === null) {
123 3
            $client = new Client();
124
        }
125 9
        if ($request === null) {
126 6
            $request = new Request('GET', $url);
127
        }
128
129 9
        $response = $client->sendRequest($request);
130 9
        $content = $response->getBody()->getContents();
131
132 9
        return $this->loadStr($content, $options);
133
    }
134
135
    /**
136
     * Parsers the html of the given string. Used for load(), loadFromFile(),
137
     * and loadFromUrl().
138
     *
139
     * @throws ChildNotFoundException
140
     * @throws CircularException
141
     * @throws Exceptions\ContentLengthException
142
     * @throws LogicalException
143
     * @throws StrictException
144
     */
145 294
    public function loadStr(string $str, ?Options $options = null): Dom
146
    {
147 294
        $localOptions = new Options();
148 294
        if ($this->globalOptions !== null) {
149 75
            $localOptions = $localOptions->setFromOptions($this->globalOptions);
150
        }
151 294
        if ($options !== null) {
152 12
            $localOptions = $localOptions->setFromOptions($options);
153
        }
154
155 294
        $html = $this->domCleaner->clean($str, $localOptions, $this->defaultCharset);
156
157 294
        $this->content = new Content($html);
158
159 294
        $this->root = $this->domParser->parse($localOptions, $this->content, \strlen($str));
160 288
        $this->domParser->detectCharset($localOptions, $this->defaultCharset, $this->root);
161
162 288
        return $this;
163
    }
164
165
    /**
166
     * Sets a global options array to be used by all load calls.
167
     */
168 75
    public function setOptions(Options $options): Dom
169
    {
170 75
        $this->globalOptions = $options;
171
172 75
        return $this;
173
    }
174
175
    /**
176
     * Find elements by css selector on the root node.
177
     *
178
     * @throws NotLoadedException
179
     * @throws ChildNotFoundException
180
     *
181
     * @return mixed|Collection|null
182
     */
183 213
    public function find(string $selector, int $nth = null)
184
    {
185 213
        $this->isLoaded();
186
187 210
        return $this->root->find($selector, $nth);
188
    }
189
190
    /**
191
     * Simple wrapper function that returns an element by the
192
     * id.
193
     *
194
     * @param $id
195
     *
196
     * @throws NotLoadedException
197
     * @throws ChildNotFoundException
198
     *
199
     * @return mixed|Collection|null
200
     */
201 12
    public function getElementById($id)
202
    {
203 12
        $this->isLoaded();
204
205 12
        return $this->find('#' . $id, 0);
206
    }
207
208
    /**
209
     * Simple wrapper function that returns all elements by
210
     * tag name.
211
     *
212
     * @throws NotLoadedException
213
     * @throws ChildNotFoundException
214
     *
215
     * @return mixed|Collection|null
216
     */
217 15
    public function getElementsByTag(string $name)
218
    {
219 15
        $this->isLoaded();
220
221 15
        return $this->find($name);
222
    }
223
224
    /**
225
     * Simple wrapper function that returns all elements by
226
     * class name.
227
     *
228
     * @throws NotLoadedException
229
     * @throws ChildNotFoundException
230
     *
231
     * @return mixed|Collection|null
232
     */
233 3
    public function getElementsByClass(string $class)
234
    {
235 3
        $this->isLoaded();
236
237 3
        return $this->find('.' . $class);
238
    }
239
240
    /**
241
     * Checks if the load methods have been called.
242
     *
243
     * @throws NotLoadedException
244
     */
245 279
    private function isLoaded(): void
246
    {
247 279
        if (\is_null($this->content)) {
248 3
            throw new NotLoadedException('Content is not loaded!');
249
        }
250 276
    }
251
}
252