Passed
Branch dev/3.0.0 (c487fc)
by Gilles
01:48
created

Dom::getElementsByClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPHtmlParser;
6
7
use GuzzleHttp\Psr7\Request;
8
use Http\Adapter\Guzzle6\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 294
    public function __construct(?ParserInterface $domParser = null, ?CleanerInterface $domCleaner = null)
64
    {
65 294
        if ($domParser === null) {
66 294
            $domParser = DomParserDiscovery::find();
67
        }
68 294
        if ($domCleaner === null) {
69 294
            $domCleaner = CleanerDiscovery::find();
70
        }
71
72 294
        $this->domParser = $domParser;
73 294
        $this->domCleaner = $domCleaner;
74 294
    }
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 6
    public function loadFromUrl(string $url, ?Options $options, ?ClientInterface $client = null, ?RequestInterface $request = null): Dom
121
    {
122 6
        if ($client === null) {
123
            $client = new Client();
124
        }
125 6
        if ($request === null) {
126 3
            $request = new Request('GET', $url);
127
        }
128
129 6
        $response = $client->sendRequest($request);
130 6
        $content = $response->getBody()->getContents();
131
132 6
        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 285
    public function loadStr(string $str, ?Options $options = null): Dom
146
    {
147 285
        $localOptions = new Options();
148 285
        if ($this->globalOptions !== null) {
149 75
            $localOptions = $localOptions->setFromOptions($this->globalOptions);
150
        }
151 285
        if ($options !== null) {
152 9
            $localOptions = $localOptions->setFromOptions($options);
153
        }
154
155 285
        $html = $this->domCleaner->clean($str, $localOptions);
156
157 285
        $this->content = new Content($html);
158
159 285
        $this->root = $this->domParser->parse($localOptions, $this->content, strlen($str));
160 279
        $this->domParser->detectCharset($localOptions, $this->defaultCharset, $this->root);
161
162 279
        return $this;
163
    }
164
165
    /**
166
     * Sets a global options array to be used by all load calls.
167
     *
168
     *
169
     */
170 75
    public function setOptions(Options $options): Dom
171
    {
172 75
        $this->globalOptions = $options;
173
174 75
        return $this;
175
    }
176
177
    /**
178
     * Find elements by css selector on the root node.
179
     *
180
     * @return mixed|Collection|null
181
     * @throws NotLoadedException
182
     *
183
     * @throws ChildNotFoundException
184
     */
185 213
    public function find(string $selector, int $nth = null)
186
    {
187 213
        $this->isLoaded();
188
189 210
        return $this->root->find($selector, $nth);
190
    }
191
192
    /**
193
     * Simple wrapper function that returns an element by the
194
     * id.
195
     *
196
     * @param $id
197
     *
198
     * @return mixed|Collection|null
199
     * @throws NotLoadedException
200
     *
201
     * @throws ChildNotFoundException
202
     */
203 12
    public function getElementById($id)
204
    {
205 12
        $this->isLoaded();
206
207 12
        return $this->find('#' . $id, 0);
208
    }
209
210
    /**
211
     * Simple wrapper function that returns all elements by
212
     * tag name.
213
     *
214
     * @return mixed|Collection|null
215
     * @throws NotLoadedException
216
     *
217
     * @throws ChildNotFoundException
218
     */
219 15
    public function getElementsByTag(string $name)
220
    {
221 15
        $this->isLoaded();
222
223 15
        return $this->find($name);
224
    }
225
226
    /**
227
     * Simple wrapper function that returns all elements by
228
     * class name.
229
     *
230
     * @return mixed|Collection|null
231
     * @throws NotLoadedException
232
     *
233
     * @throws ChildNotFoundException
234
     */
235 3
    public function getElementsByClass(string $class)
236
    {
237 3
        $this->isLoaded();
238
239 3
        return $this->find('.' . $class);
240
    }
241
242
    /**
243
     * Checks if the load methods have been called.
244
     *
245
     * @throws NotLoadedException
246
     */
247 270
    private function isLoaded(): void
248
    {
249 270
        if (\is_null($this->content)) {
250 3
            throw new NotLoadedException('Content is not loaded!');
251
        }
252
    }
253
}