Completed
Push — master ( 51bd4b...f1ece3 )
by Joseph
02:11
created

PreviewBuilder::formatUrl()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 4
Bugs 1 Features 2
Metric Value
c 4
b 1
f 2
dl 0
loc 20
ccs 11
cts 11
cp 1
rs 8.8571
cc 5
eloc 11
nc 7
nop 1
crap 5
1
<?php
2
3
namespace Jclyons52\PagePreview;
4
5
use Jclyons52\PHPQuery\Document;
6
7
class PreviewBuilder
8
{
9
10
    /**
11
     * PHPQuery document object that will be used to select elements
12
     * @var \Jclyons52\PHPQuery\Document
13
     */
14
    public $document;
15
16
    /**
17
     * reference to the url parameter the user passes into the fetch method
18
     * @var string
19
     */
20
    public $url;
21
22
    /**
23
     * destructured array of url components from parse_url
24
     * @var array
25
     */
26
    protected $urlComponents;
27
28
    /**
29
     * @var HttpInterface
30
     */
31
    protected $http;
32
33 81
    public function __construct(HttpInterface $http)
34
    {
35 81
        $this->http = $http;
36 81
    }
37
38
    /**
39
     * Instantiate class with dependencies
40
     * @return static
41
     */
42 36
    public static function create()
43
    {
44 3
        $http = new Http();
45 3
        return new PreviewBuilder($http);
46 36
    }
47
    
48
    /**
49
     * @param string $url
50
     * @return Preview
51
     * @throws \Exception
52
     */
53 45
    public function fetch($url)
54
    {
55 45
        $this->url = new Url($url);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Jclyons52\PagePreview\Url($url) of type object<Jclyons52\PagePreview\Url> is incompatible with the declared type string of property $url.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
56
57 42
        $body = $this->http->get($url);
58
59 42
        if ($body === false) {
60 3
            throw new \Exception('failed to load page');
61
        }
62
63 39
        $this->document = new Document($body);
64
65 39
        return $this->getPreview();
66
    }
67
68
    /**
69
     * @return string
70
     */
71 39
    public function title()
72
    {
73 39
        return $this->document->querySelector('title')->text();
74
    }
75
76
    /**
77
     * @return mixed
78
     */
79 39
    public function metaKeywords()
80
    {
81 39
        $keywordsElement = $this->document->querySelector('meta[name="keywords"]');
82
83 39
        if (!$keywordsElement) {
84 6
            return [];
85
        }
86
87 33
        $keywordString = $keywordsElement->attr('content');
88
89 33
        $keywords = explode(',', $keywordString);
90
91 33
        return array_map(function ($word) {
92 33
            return trim($word);
93
94 33
        }, $keywords);
95
    }
96
97
    /**
98
     * @param string $element
99
     * @return array
100
     */
101 39
    public function meta($element = null)
102
    {
103 39
        $selector = "meta";
104 39
        if ($element !== null) {
105 39
            $selector .= "[name='{$element}']";
106 39
            $metaTags =  $this->document->querySelector($selector);
107 39
            if ($metaTags === null) {
108 6
                return null;
109
            }
110 33
            return  $metaTags->attr('content');
111
        }
112 39
        $metaTags = $this->document->querySelectorAll($selector);
113
114 39
        return $this->metaTagsToArray($metaTags);
115
    }
116
117
    /**
118
     * get source attributes of all image tags on the page
119
     * @return array<String>
120
     */
121 39
    public function images()
122
    {
123 39
        $images = $this->document->querySelectorAll('img');
124
125 39
        if ($images === []) {
126 3
            return [];
127
        }
128 36
        $urls = $images->attr('src');
129 36
        $result = [];
130 36
        foreach ($urls as $url) {
131 36
            $result[] = $this->url->formatRelativeToAbsolute($url);
0 ignored issues
show
Bug introduced by
The method formatRelativeToAbsolute cannot be called on $this->url (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
132 36
        }
133 36
        return $result;
134
    }
135
136
    /**
137
     * returns an instance of Preview
138
     * @return Preview
139
     */
140 39
    public function getPreview()
141
    {
142 39
        $title = $this->title();
143
144 39
        $images = $this->images();
145
146 39
        $description = $this->meta('description');
147
148 39
        $meta = $this->meta();
149
150 39
        $keywords =  $this->metaKeywords();
151
152 39
        if ($keywords !== []) {
153 33
            $meta['keywords'] = $keywords;
154 33
        }
155
156 39
        $media = new Media($this->http);
157
        
158 39
        return new Preview($media, [
159 39
            'title' => $title,
160 39
            'images' => $images,
161 39
            'description' => $description,
162 39
            'url' => $this->url->original,
163 39
            'meta' => $meta,
164 39
        ]);
165
    }
166
167
    /**
168
     * @param \Jclyons52\PHPQuery\Support\NodeCollection $metaTags
169
     * @return array
170
     */
171 39
    private function metaTagsToArray($metaTags)
172
    {
173 39
        $values = [];
174 39
        foreach ($metaTags as $meta) {
175 39
            $name = $meta->attr('name');
176 39
            if ($name === '') {
177 39
                $name = $meta->attr('property');
178 39
            }
179 39
            $content = $meta->attr('content');
180 39
            if ($name === '' || $content == '') {
181 39
                continue;
182
            }
183 33
            $values[$name] = $content;
184 39
        }
185 39
        return $values;
186
    }
187
}
188