Movie   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Test Coverage

Coverage 19.67%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 17
eloc 54
c 4
b 0
f 0
dl 0
loc 164
ccs 12
cts 61
cp 0.1967
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A extractId() 0 13 3
A getImdbUrl() 0 3 1
A getTitle() 0 8 2
A setSource() 0 9 3
A getStatus() 0 3 1
A paddedId() 0 3 1
A setStatus() 0 5 1
A fetchData() 0 38 3
A setId() 0 10 2
1
<?php
2
3
namespace mQueue\Model;
4
5
use DOMDocument;
6
use DOMXPath;
7
use Exception;
8
use Zend_Date;
9
10
/**
11
 * A movie
12
 */
13
class Movie extends AbstractModel
14
{
15
    /**
16
     * Extract IMDb id from URL
17
     *
18
     * @param string $string
19
     *
20
     * @return null|string the id extracted
21
     */
22 2
    public static function extractId(?string $string): ?string
23
    {
24 2
        if (!$string) {
25 2
            return null;
26
        }
27
28 1
        $string = self::paddedId($string);
29 1
        preg_match_all("/(\d{7,})/", $string, $r);
30 1
        if (isset($r[1][0])) {
31 1
            return $r[1][0];
32
        }
33
34
        return null;
35
    }
36
37
    /**
38
     * Returns the ID for IMDb with padded 0
39
     *
40
     * @param string $id
41
     *
42
     * @return string the id extracted
43
     */
44 1
    public static function paddedId(string $id): string
45
    {
46 1
        return str_pad($id, 7, '0', STR_PAD_LEFT);
47
    }
48
49
    /**
50
     * Returns the title, if needed fetch the title from IMDb
51
     *
52
     * @return string
53
     */
54 1
    public function getTitle()
55
    {
56
        // If we didn't get the title yet, fetch it and save in our database
57 1
        if (!($this->title)) {
58
            $this->fetchData();
59
        }
60
61 1
        return $this->title;
62
    }
63
64
    /**
65
     * Fetch data from IMDb and store in database (possibly overwriting)
66
     */
67
    public function fetchData(): void
68
    {
69
        $ch = curl_init($this->getImdbUrl());
70
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Accept-Language: en-US,en;q=0.8']);
71
        curl_setopt($ch, CURLOPT_HEADER, false);
72
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
73
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
74
75
        $file = curl_exec($ch);
76
        curl_close($ch);
77
78
        $document = new DOMDocument();
79
        @$document->loadHTML($file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for loadHTML(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

79
        /** @scrutinizer ignore-unhandled */ @$document->loadHTML($file);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Bug introduced by
It seems like $file can also be of type true; however, parameter $source of DOMDocument::loadHTML() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

79
        @$document->loadHTML(/** @scrutinizer ignore-type */ $file);
Loading history...
80
        $xpath = new DOMXPath($document);
81
82
        // Extract title
83
        $titleEntries = $xpath->evaluate('//meta[contains(@property, "og:title")]/@content');
84
        if ($titleEntries->length == 1) {
85
            $rawTitle = $titleEntries->item(0)->value;
86
            $this->title = preg_replace('~ - IMDb$~', '', $rawTitle);
0 ignored issues
show
Bug Best Practice introduced by
The property title does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
87
        } else {
88
            $this->title = '[title not available, could not fetch from IMDb]';
89
90
            return; // If there is not even title give up everything
91
        }
92
93
        // Extract release date
94
        $jsonLd = $xpath->evaluate('//script[@type="application/ld+json"]/text()');
95
        if ($jsonLd->length == 1) {
96
            $json = json_decode($jsonLd->item(0)->data, true);
97
            $this->dateRelease = $json['datePublished'] ?? null;
0 ignored issues
show
Bug Best Practice introduced by
The property dateRelease does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
98
        } else {
99
            $this->dateRelease = null;
100
        }
101
102
        $this->dateUpdate = Zend_Date::now()->get(Zend_Date::ISO_8601);
0 ignored issues
show
Bug Best Practice introduced by
The property dateUpdate does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
103
        $this->setReadOnly(false); // If the movie is coming from a joined query, we need to set non-readonly before saving
104
        $this->save();
105
    }
106
107
    /**
108
     * Sets the ID for the movie from any string containing a valid ID
109
     *
110
     * @param string $id
111
     *
112
     * @return Movie
113
     */
114
    public function setId($id)
115
    {
116
        $extractedId = self::extractId($id);
117
        if (!$extractedId) {
118
            throw new Exception(sprintf('Invalid Id for movie. Given "%1$s", extracted "%2$s"', $id, $extractedId));
119
        }
120
121
        $this->id = $extractedId;
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
122
123
        return $this;
124
    }
125
126
    /**
127
     * Returns the IMDb url for the movie
128
     *
129
     * @return string
130
     */
131
    public function getImdbUrl(): string
132
    {
133
        return 'https://www.imdb.com/title/tt' . self::paddedId($this->id) . '/';
134
    }
135
136
    /**
137
     * Returns the status for this movie and the specified user
138
     *
139
     * @param User $user
140
     *
141
     * @return Status
142
     */
143
    public function getStatus(User $user = null)
144
    {
145
        return StatusMapper::find($this->id, $user);
146
    }
147
148
    /**
149
     * Set the status for the specified user
150
     *
151
     * @param User $user
152
     * @param int $rating @see \mQueue\Model\Status
153
     *
154
     * @return Status
155
     */
156
    public function setStatus(User $user, $rating)
157
    {
158
        $status = StatusMapper::set($this, $user, $rating);
159
160
        return $status;
161
    }
162
163
    /**
164
     * Set the source for the movie if any. In any case record the search date and count
165
     *
166
     * @param array|false $source
167
     */
168
    public function setSource($source): void
169
    {
170
        $this->dateSearch = Zend_Date::now()->get(Zend_Date::ISO_8601);
0 ignored issues
show
Bug Best Practice introduced by
The property dateSearch does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
171
        ++$this->searchCount;
0 ignored issues
show
Bug Best Practice introduced by
The property searchCount does not exist on mQueue\Model\Movie. Since you implemented __get, consider adding a @property annotation.
Loading history...
172
        if ($source && @$source['score']) {
173
            $this->identity = $source['identity'];
0 ignored issues
show
Bug Best Practice introduced by
The property identity does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
174
            $this->quality = $source['quality'];
0 ignored issues
show
Bug Best Practice introduced by
The property quality does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
175
            $this->score = $source['score'];
0 ignored issues
show
Bug Best Practice introduced by
The property score does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
176
            $this->source = $source['link'];
0 ignored issues
show
Bug Best Practice introduced by
The property source does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
177
        }
178
    }
179
}
180