Completed
Push — master ( b623ba...fc6e2c )
by Joseph
02:37
created

PreviewBuilder::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
66
67 39
        $result = $this->client->request('GET', $url);
68
69 36
        $body = $result->getBody()->getContents();
70
71 36
        $this->document = new Document($body);
72
73 36
        return $this->getPreview();
74
    }
75
76
    /**
77
     * @return string
78
     */
79 36
    public function title()
80
    {
81 36
        return $this->document->querySelector('title')->text();
82
    }
83
84
    /**
85
     * @return mixed
86
     */
87 36
    public function metaKeywords()
88
    {
89 36
        $keywordsElement = $this->document->querySelector('meta[name="keywords"]');
90
91 36
        if (!$keywordsElement) {
92 6
            return [];
93
        }
94
95 30
        $keywordString = $keywordsElement->attr('content');
96
97 30
        $keywords = explode(',', $keywordString);
98
99 30
        return array_map(function ($word) {
100 30
            return trim($word);
101
102 30
        }, $keywords);
103
    }
104
105
    /**
106
     * @param string $element
107
     * @return array
108
     */
109 36
    public function meta($element = null)
110
    {
111 36
        $selector = "meta";
112 36
        if ($element !== null) {
113 36
            $selector .= "[name='{$element}']";
114 36
            $metaTags =  $this->document->querySelector($selector);
115 36
            if ($metaTags === null) {
116 6
                return null;
117
            }
118 30
            return  $metaTags->attr('content');
119
        }
120 36
        $metaTags = $this->document->querySelectorAll($selector);
121
122 36
        return $this->metaTagsToArray($metaTags);
123
    }
124
125
    /**
126
     * get source attributes of all image tags on the page
127
     * @return array<String>
128
     */
129 36
    public function images()
130
    {
131 36
        $images = $this->document->querySelectorAll('img');
132
133 36
        if ($images === []) {
134 3
            return [];
135
        }
136
137 33
        $urls = $images->attr('src');
138 33
        $result = [];
139 33
        foreach ($urls as $url) {
140 33
            $result[] = $this->formatUrl($url);
141 33
        }
142 33
        return $result;
143
    }
144
145
    /**
146
     * returns a string of the link preview html
147
     * @param  string $type     template name to be selected
0 ignored issues
show
Bug introduced by
There is no parameter named $type. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
148
     * @param  string $viewPath path to templates folder
0 ignored issues
show
Bug introduced by
There is no parameter named $viewPath. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
149
     * @return string           html for link preview
150
     */
151 36
    public function getPreview()
152
    {
153 36
        $title = $this->title();
154
155 36
        $images = $this->images();
156
157 36
        $description = $this->meta('description');
158
159 36
        $meta = $this->meta();
160
161 36
        $keywords =  $this->metaKeywords();
162
163 36
        if ($keywords !== []) {
164 30
            $meta['keywords'] = $keywords;
165 30
        }
166
167 36
        return new Preview([
168 36
            'title' => $title,
169 36
            'images' => $images,
170 36
            'description' => $description,
171 36
            'url' => $this->url,
172 36
            'meta' => $meta,
173 36
        ]);
174
    }
175
176
    /**
177
     * @param string $url
178
     * @return string
179
     */
180 33
    private function formatUrl($url)
181
    {
182 33
        $path = array_key_exists('path', $this->urlComponents) ? $this->urlComponents['path'] : '';
183
184 33
        if (filter_var($url, FILTER_VALIDATE_URL) !== false) {
185 33
            return $url;
186
        }
187 33
        if (substr($url, 0, 1) === '/') {
188 33
            return 'http://' . $this->urlComponents['host'] . $url;
189
        }
190 33
        return 'http://' . $this->urlComponents['host'] .$path . '/' . $url;
191
    }
192
193
    /**
194
     * @param $metaTags
195
     * @return array
196
     */
197 36
    private function metaTagsToArray($metaTags)
198
    {
199 36
        $values = [];
200 36
        foreach ($metaTags as $meta) {
201 36
            $name = $meta->attr('name');
202 36
            if ($name === '') {
203 36
                $name = $meta->attr('property');
204 36
            }
205 36
            $content = $meta->attr('content');
206 36
            if ($name === '' || $content == '') {
207 36
                continue;
208
            }
209 30
            $values[$name] = $content;
210 36
        }
211
212 36
        return $values;
213
    }
214
}
215