Passed
Push — master ( c706a5...106168 )
by Jeroen
01:36
created

Diglett::__construct()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 6
nop 2
dl 0
loc 19
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
namespace Jerodev\Diglett;
4
5
use Symfony\Component\DomCrawler\Crawler;
6
7
class Diglett
8
{
9
    /**
10
     *  The Symfony DomCrawler to work with.
11
     *
12
     *  @var Crawler
13
     */
14
    private $crawler;
15
16
    /**
17
     *  An array of special ICssFilter's
18
     *
19
     *  @var array
20
     */
21
    private $cssFilters;
22
23
    /**
24
     *  Create a diglett instance from a Symfony Crawler.
25
     *
26
     *  @param Crawler
27
     *  @param array|null $cssFilters
28
     */
29
    public function __construct(Crawler $crawler, ?array $cssFilters = null)
30
    {
31
        $this->crawler = $crawler;
32
33
        // If no css filters are set, add the default list
34
        if ($cssFilters === null)
35
        {
36
            $cssFilters = [
37
                CssFilters\FirstFilter::class,
38
                CssFilters\NthFilter::class
39
            ];
40
        }
41
        $this->cssFilters = [];
42
        foreach ($cssFilters as $filter)
43
        {
44
            if (!class_exists($filter) || !in_array(CssFilters\ICssFilter::class, class_implements($filter)))
45
                throw new \ErrorException("All CssFilters should implement ICssFilter, '$filter' does not.");
46
47
            $this->cssFilters[$filter::getFunctionName()] = $filter;
48
        }
49
    }
50
51
    /**
52
     *  Get the underlying crawler object
53
     *
54
     *  @return Crawler
55
     */
56
    public function getCrawler(): Crawler
57
    {
58
        return $this->crawler;
59
    }
60
61
62
    /**
63
     *  Use special css selectors to fetch several values
64
     *
65
     *  @param array $selectors
66
     *  @return array
67
     */
68
    public function getTexts(array $selectors): array
69
    {
70
        $results = [];
71
        foreach ($selectors as $key => $value)
72
        {
73
            $results[$key] = $this->getText($value);
74
        }
75
76
        return $results;
77
    }
78
79
    /**
80
     *  Get the value for a single special css selector
81
     *
82
     *  @param string $selector
83
     *  @return string|null
84
     */
85
    public function getText(string $selector): ?string
86
    {
87
        $attribute = null;
88
        $selector = preg_replace_callback(
89
            '/\{(.*?)\}$/',
90
            function ($matches) use (&$attribute) {
91
                $attribute = $matches[1] ?? null;
92
            },
93
            $selector
94
        );
95
96
        $parsedSelector = CssFilterParser::parse($selector, $this->cssFilters);
97
98
        $crawler = $this->crawler;
99
        foreach ($parsedSelector as $part)
100
        {
101
            $crawler = $crawler->filter($part['selector']);
102
103
            foreach ($part['functions'] as $function)
104
            {
105
                $crawler = $function->filterNodes($crawler);
106
            }
107
108
            if (empty($crawler) || $crawler->count() === 0)
109
            {
110
                return null;
111
            }
112
        }
113
114
        return $attribute === null ? $crawler->text() : $crawler->attr($attribute);
115
    }
116
}
117