Passed
Push — master ( 3db12d...858816 )
by Sébastien
03:31
created

Book::getThumbnail()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 34
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7.0046

Importance

Changes 0
Metric Value
cc 7
eloc 24
nc 6
nop 3
dl 0
loc 34
ccs 21
cts 22
cp 0.9545
crap 7.0046
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * COPS (Calibre OPDS PHP Server) class file
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Sébastien Lucas <[email protected]>
7
 */
8
9
// Silly thing because PHP forbid string concatenation in class const
10
define ('SQL_BOOKS_LEFT_JOIN', 'left outer join comments on comments.book = books.id
11
                                left outer join books_ratings_link on books_ratings_link.book = books.id
12
                                left outer join ratings on books_ratings_link.rating = ratings.id ');
13
define ('SQL_BOOKS_ALL', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . ' order by books.sort ');
14
define ('SQL_BOOKS_BY_PUBLISHER', 'select {0} from books_publishers_link, books ' . SQL_BOOKS_LEFT_JOIN . '
15
                                                    where books_publishers_link.book = books.id and publisher = ? {1} order by publisher');
16
define ('SQL_BOOKS_BY_FIRST_LETTER', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
17
                                                    where upper (books.sort) like ? order by books.sort');
18
define ('SQL_BOOKS_BY_AUTHOR', 'select {0} from books_authors_link, books ' . SQL_BOOKS_LEFT_JOIN . '
19
                                                    left outer join books_series_link on books_series_link.book = books.id
20
                                                    where books_authors_link.book = books.id and author = ? {1} order by series desc, series_index asc, pubdate asc');
21
define ('SQL_BOOKS_BY_SERIE', 'select {0} from books_series_link, books ' . SQL_BOOKS_LEFT_JOIN . '
22
                                                    where books_series_link.book = books.id and series = ? {1} order by series_index');
23
define ('SQL_BOOKS_BY_TAG', 'select {0} from books_tags_link, books ' . SQL_BOOKS_LEFT_JOIN . '
24
                                                    where books_tags_link.book = books.id and tag = ? {1} order by sort');
25
define ('SQL_BOOKS_BY_LANGUAGE', 'select {0} from books_languages_link, books ' . SQL_BOOKS_LEFT_JOIN . '
26
                                                    where books_languages_link.book = books.id and lang_code = ? {1} order by sort');
27
define ('SQL_BOOKS_BY_CUSTOM', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
28
                                                    where {2}.book = books.id and {2}.{3} = ? {1} order by sort');
29
define ('SQL_BOOKS_BY_CUSTOM_BOOL_TRUE', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
30
                                                    where {2}.book = books.id and {2}.value = 1 {1} order by sort');
31
define ('SQL_BOOKS_BY_CUSTOM_BOOL_FALSE', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
32
                                                    where {2}.book = books.id and {2}.value = 0 {1} order by sort');
33
define ('SQL_BOOKS_BY_CUSTOM_BOOL_NULL', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
34
                                                    where books.id not in (select book from {2}) {1} order by sort');
35
define ('SQL_BOOKS_BY_CUSTOM_RATING', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
36
                                                    left join {2} on {2}.book = books.id
37
                                                    left join {3} on {3}.id = {2}.{4}
38
                                                    where {3}.value = ?  order by sort');
39
define ('SQL_BOOKS_BY_CUSTOM_RATING_NULL', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
40
								                    left join {2} on {2}.book = books.id
41
								                    left join {3} on {3}.id = {2}.{4}
42
                                                    where ((books.id not in (select {2}.book from {2})) or ({3}.value = 0)) {1} order by sort');
43
define ('SQL_BOOKS_BY_CUSTOM_DATE', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
44
                                                    where {2}.book = books.id and date({2}.value) = ? {1} order by sort');
45
define ('SQL_BOOKS_BY_CUSTOM_DIRECT', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
46
                                                    where {2}.book = books.id and {2}.value = ? {1} order by sort');
47
define ('SQL_BOOKS_BY_CUSTOM_DIRECT_ID', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
48
                                                    where {2}.book = books.id and {2}.id = ? {1} order by sort');
49
define ('SQL_BOOKS_QUERY', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
50
                                                    where (
51
                                                    exists (select null from authors, books_authors_link where book = books.id and author = authors.id and authors.name like ?) or
52
                                                    exists (select null from tags, books_tags_link where book = books.id and tag = tags.id and tags.name like ?) or
53
                                                    exists (select null from series, books_series_link on book = books.id and books_series_link.series = series.id and series.name like ?) or
54
                                                    exists (select null from publishers, books_publishers_link where book = books.id and books_publishers_link.publisher = publishers.id and publishers.name like ?) or
55
                                                    title like ?) {1} order by books.sort');
56
define ('SQL_BOOKS_RECENT', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
57
                                                    where 1=1 {1} order by timestamp desc limit ');
58
define ('SQL_BOOKS_BY_RATING', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
59
                                                    where books_ratings_link.book = books.id and ratings.id = ? {1} order by sort');
60
61
class Book extends Base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
62
{
63
    const ALL_BOOKS_UUID = 'urn:uuid';
64
    const ALL_BOOKS_ID = 'cops:books';
65
    const ALL_RECENT_BOOKS_ID = 'cops:recentbooks';
66
    const BOOK_COLUMNS = 'books.id as id, books.title as title, text as comment, path, timestamp, pubdate, series_index, uuid, has_cover, ratings.rating';
67
68
    const SQL_BOOKS_LEFT_JOIN = SQL_BOOKS_LEFT_JOIN;
69
    const SQL_BOOKS_ALL = SQL_BOOKS_ALL;
70
    const SQL_BOOKS_BY_PUBLISHER = SQL_BOOKS_BY_PUBLISHER;
71
    const SQL_BOOKS_BY_FIRST_LETTER = SQL_BOOKS_BY_FIRST_LETTER;
72
    const SQL_BOOKS_BY_AUTHOR = SQL_BOOKS_BY_AUTHOR;
73
    const SQL_BOOKS_BY_SERIE = SQL_BOOKS_BY_SERIE;
74
    const SQL_BOOKS_BY_TAG = SQL_BOOKS_BY_TAG;
75
    const SQL_BOOKS_BY_LANGUAGE = SQL_BOOKS_BY_LANGUAGE;
76
    const SQL_BOOKS_BY_CUSTOM = SQL_BOOKS_BY_CUSTOM;
77
    const SQL_BOOKS_BY_CUSTOM_BOOL_TRUE = SQL_BOOKS_BY_CUSTOM_BOOL_TRUE;
78
    const SQL_BOOKS_BY_CUSTOM_BOOL_FALSE = SQL_BOOKS_BY_CUSTOM_BOOL_FALSE;
79
    const SQL_BOOKS_BY_CUSTOM_BOOL_NULL = SQL_BOOKS_BY_CUSTOM_BOOL_NULL;
80
    const SQL_BOOKS_BY_CUSTOM_RATING = SQL_BOOKS_BY_CUSTOM_RATING;
81
    const SQL_BOOKS_BY_CUSTOM_RATING_NULL = SQL_BOOKS_BY_CUSTOM_RATING_NULL;
82
    const SQL_BOOKS_BY_CUSTOM_DATE = SQL_BOOKS_BY_CUSTOM_DATE;
83
    const SQL_BOOKS_BY_CUSTOM_DIRECT = SQL_BOOKS_BY_CUSTOM_DIRECT;
84
    const SQL_BOOKS_BY_CUSTOM_DIRECT_ID = SQL_BOOKS_BY_CUSTOM_DIRECT_ID;
85
    const SQL_BOOKS_QUERY = SQL_BOOKS_QUERY;
86
    const SQL_BOOKS_RECENT = SQL_BOOKS_RECENT;
87
    const SQL_BOOKS_BY_RATING = SQL_BOOKS_BY_RATING;
88
89
    const BAD_SEARCH = 'QQQQQ';
90
91
    public $id;
92
    public $title;
93
    public $timestamp;
94
    public $pubdate;
95
    public $path;
96
    public $uuid;
97
    public $hasCover;
98
    public $relativePath;
99
    public $seriesIndex;
100
    public $comment;
101
    public $rating;
102
    public $datas = NULL;
103
    public $authors = NULL;
104
    public $publisher = NULL;
105
    public $serie = NULL;
106
    public $tags = NULL;
107
    public $languages = NULL;
108
    public $format = array ();
109
110
111 78
    public function __construct($line) {
112 78
        $this->id = $line->id;
113 78
        $this->title = $line->title;
114 78
        $this->timestamp = strtotime($line->timestamp);
115 78
        $this->pubdate = $line->pubdate;
116 78
        $this->path = Base::getDbDirectory() . $line->path;
117 78
        $this->relativePath = $line->path;
118 78
        $this->seriesIndex = $line->series_index;
119 78
        $this->comment = $line->comment;
120 78
        $this->uuid = $line->uuid;
121 78
        $this->hasCover = $line->has_cover;
122 78
        if (!file_exists($this->getFilePath('jpg'))) {
123
            // double check
124 44
            $this->hasCover = 0;
125
        }
126 78
        $this->rating = $line->rating;
127 78
    }
128
129 42
    public function getEntryId() {
130 42
        return self::ALL_BOOKS_UUID.':'.$this->uuid;
131
    }
132
133 4
    public static function getEntryIdByLetter ($startingLetter) {
134 4
        return self::ALL_BOOKS_ID.':letter:'.$startingLetter;
135
    }
136
137 3
    public function getUri () {
138 3
        return '?page='.parent::PAGE_BOOK_DETAIL.'&id=' . $this->id;
139
    }
140
141 3
    public function getDetailUrl () {
142 3
        $urlParam = $this->getUri();
143 3 View Code Duplication
        if (!is_null(GetUrlParam(DB))) $urlParam = addURLParameter($urlParam, DB, GetUrlParam (DB));
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
144 3
        return 'index.php' . $urlParam;
145
    }
146
147 43
    public function getTitle () {
148 43
        return $this->title;
149
    }
150
151
    /* Other class (author, series, tag, ...) initialization and accessors */
152
153
    /**
154
     * @return Author[]
155
     */
156 49
    public function getAuthors () {
157 49
        if (is_null($this->authors)) {
158 49
            $this->authors = Author::getAuthorByBookId($this->id);
159
        }
160 49
        return $this->authors;
161
    }
162
163
    public function getAuthorsName () {
164
        return implode(', ', array_map(function ($author) { return $author->name; }, $this->getAuthors()));
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
165
    }
166
167
    public function getAuthorsSort () {
168
        return implode(', ', array_map(function ($author) { return $author->sort; }, $this->getAuthors()));
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
169
    }
170
171 5
    public function getPublisher () {
172 5
        if (is_null($this->publisher)) {
173 5
            $this->publisher = Publisher::getPublisherByBookId($this->id);
174
        }
175 5
        return $this->publisher;
176
    }
177
178
    /**
179
     * @return Serie
180
     */
181 48
    public function getSerie() {
182 48
        if (is_null($this->serie)) {
183 48
            $this->serie = Serie::getSerieByBookId($this->id);
184
        }
185 48
        return $this->serie;
186
    }
187
188
    /**
189
     * @return string
190
     */
191 10
    public function getLanguages() {
192 10
        $lang = array();
193 10
        $result = parent::getDb()->prepare('select languages.lang_code
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getDb() instead of getLanguages()). Are you sure this is correct? If so, you might want to change this to $this->getDb().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
194
                from books_languages_link, languages
195
                where books_languages_link.lang_code = languages.id
196
                and book = ?
197
                order by item_order');
198 10
        $result->execute(array($this->id));
199 10
        while ($post = $result->fetchObject())
200
        {
201 10
            array_push($lang, Language::getLanguageString($post->lang_code));
202
        }
203 10
        return implode(', ', $lang);
204
    }
205
206
    /**
207
     * @return Tag[]
208
     */
209 10
    public function getTags() {
210 10
        if (is_null ($this->tags)) {
211 10
            $this->tags = array();
212
213 10
            $result = parent::getDb()->prepare('select tags.id as id, name
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getDb() instead of getTags()). Are you sure this is correct? If so, you might want to change this to $this->getDb().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
214
                from books_tags_link, tags
215
                where tag = tags.id
216
                and book = ?
217
                order by name');
218 10
            $result->execute(array($this->id));
219 10
            while ($post = $result->fetchObject())
220
            {
221 9
                array_push($this->tags, new Tag($post));
222
            }
223
        }
224 10
        return $this->tags;
225
    }
226
227
    public function getTagsName() {
228
        return implode(', ', array_map(function ($tag) { return $tag->name; }, $this->getTags()));
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
229
    }
230
231
    /**
232
     * @return Data[]
233
     */
234 62
    public function getDatas()
235
    {
236 62
        if (is_null($this->datas)) {
237 62
            $this->datas = Data::getDataByBook($this);
238
        }
239 62
        return $this->datas;
240
    }
241
242
    /* End of other class (author, series, tag, ...) initialization and accessors */
243
244 58
    public static function getFilterString() {
245 58
        $filter = getURLParam('tag', NULL);
246 58
        if (empty($filter)) return '';
247
248 3
        $exists = true;
249 3
        if (preg_match("/^!(.*)$/", $filter, $matches)) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal /^!(.*)$/ does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
250 1
            $exists = false;
251 1
            $filter = $matches[1];
252
        }
253
254 3
        $result = 'exists (select null from books_tags_link, tags where books_tags_link.book = books.id and books_tags_link.tag = tags.id and tags.name = "' . $filter . '")';
255
256 3
        if (!$exists) {
257 1
            $result = 'not ' . $result;
258
        }
259
260 3
        return 'and ' . $result;
261
    }
262
263 4
    public function GetMostInterestingDataToSendToKindle()
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
264
    {
265 4
        $bestFormatForKindle = array('EPUB', 'PDF', 'AZW3', 'MOBI');
266 4
        $bestRank = -1;
267 4
        $bestData = NULL;
268 4
        foreach ($this->getDatas() as $data) {
269 4
            $key = array_search($data->format, $bestFormatForKindle);
270 4
            if ($key !== false && $key > $bestRank) {
271 4
                $bestRank = $key;
272 4
                $bestData = $data;
273
            }
274
        }
275 4
        return $bestData;
276
    }
277
278 3
    public function getDataById($idData)
279
    {
280
        $reduced = array_filter($this->getDatas(), function ($data) use ($idData) {
281 3
            return $data->id == $idData;
282 3
        });
283 3
        return reset($reduced);
284
    }
285
286 8
    public function getRating() {
287 8
        if (is_null($this->rating) || $this->rating == 0) {
288 3
            return '';
289
        }
290 5
        $retour = '';
291 5
        for ($i = 0; $i < $this->rating / 2; $i++) {
292 5
            $retour .= '&#9733;';
293
        }
294 5
        for ($i = 0; $i < 5 - $this->rating / 2; $i++) {
295 3
            $retour .= '&#9734;';
296
        }
297 5
        return $retour;
298
    }
299
300 15
    public function getPubDate() {
301 15
        if (empty ($this->pubdate)) {
302 2
            return '';
303
        }
304 13
        $dateY = (int) substr($this->pubdate, 0, 4);
305 13
        if ($dateY > 102) {
306 12
            return str_pad($dateY, 4, '0', STR_PAD_LEFT);
307
        }
308 1
        return '';
309
    }
310
311 43
    public function getComment($withSerie = true) {
312 43
        $addition = '';
313 43
        $se = $this->getSerie ();
314 43
        if (!is_null ($se) && $withSerie) {
315 38
            $addition = $addition . '<strong>' . localize('content.series') . '</strong>' . str_format(localize('content.series.data'), $this->seriesIndex, htmlspecialchars($se->name)) . "<br />\n";
316
        }
317 43
        if (preg_match('/<\/(div|p|a|span)>/', $this->comment))
318
        {
319 37
            return $addition . html2xhtml($this->comment);
320
        }
321
        else
322
        {
323 31
            return $addition . htmlspecialchars($this->comment);
324
        }
325
    }
326
327
    public function getDataFormat($format) {
328 12
        $reduced = array_filter($this->getDatas(), function ($data) use ($format) {
329 12
            return $data->format == $format;
330 12
        });
331 12
        return reset($reduced);
332
    }
333
334 78
    public function getFilePath($extension, $idData = NULL, $relative = false)
335
    {
336 78
        if ($extension == 'jpg')
337
        {
338 78
            $file = 'cover.jpg';
339
        }
340
        else
341
        {
342 2
            $data = $this->getDataById($idData);
343 2
            if (!$data) return NULL;
344 2
            $file = $data->name . '.' . strtolower($data->format);
345
        }
346
347 78
        if ($relative)
348
        {
349 3
            return $this->relativePath.'/'.$file;
350
        }
351
        else
352
        {
353 78
            return $this->path.'/'.$file;
354
        }
355
    }
356
357
    public function getUpdatedEpub($idData)
358
    {
359
        global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
360
        $data = $this->getDataById($idData);
361
362
        try
363
        {
364
            $epub = new EPub($data->getLocalPath());
365
366
            $epub->Title($this->title);
367
            $authorArray = array();
368
            foreach ($this->getAuthors() as $author) {
369
                $authorArray[$author->sort] = $author->name;
370
            }
371
            $epub->Authors($authorArray);
0 ignored issues
show
Documentation introduced by
$authorArray is of type array, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
372
            $epub->Language($this->getLanguages());
373
            $epub->Description ($this->getComment(false));
374
            $epub->Subjects($this->getTagsName());
0 ignored issues
show
Documentation introduced by
$this->getTagsName() is of type string, but the function expects a false|array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
375
            $epub->Cover2($this->getFilePath('jpg'), 'image/jpeg');
0 ignored issues
show
Documentation introduced by
$this->getFilePath('jpg') is of type null|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
'image/jpeg' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
376
            $epub->Calibre($this->uuid);
377
            $se = $this->getSerie();
378
            if (!is_null($se)) {
379
                $epub->Serie($se->name);
380
                $epub->SerieIndex($this->seriesIndex);
381
            }
382
            $filename = $data->getUpdatedFilenameEpub();
383
            if ($config['cops_provide_kepub'] == '1'  && preg_match('/Kobo/', $_SERVER['HTTP_USER_AGENT'])) {
384
                $epub->updateForKepub();
385
                $filename = $data->getUpdatedFilenameKepub();
386
            }
387
            $epub->download($filename);
388
        }
389
        catch (Exception $e)
390
        {
391
            echo 'Exception : ' . $e->getMessage();
392
        }
393
    }
394
395 3
    public function getThumbnail($width, $height, $outputfile = NULL) {
396 3
        if (is_null($width) && is_null($height)) {
397 1
            return false;
398
        }
399
400 3
        $file = $this->getFilePath('jpg');
401
        // get image size
402 3
        if ($size = GetImageSize($file)) {
403 3
            $w = $size[0];
404 3
            $h = $size[1];
405
            //set new size
406 3
            if (!is_null($width)) {
407 2
                $nw = $width;
408 2
                if ($nw >= $w) { return false; }
409 1
                $nh = ($nw*$h)/$w;
410
            } else {
411 2
                $nh = $height;
412 2
                if ($nh >= $h) { return false; }
413 2
                $nw = ($nh*$w)/$h;
414
            }
415
        } else {
416
            return false;
417
        }
418
419
        //draw the image
420 2
        $src_img = imagecreatefromjpeg($file);
421 2
        $dst_img = imagecreatetruecolor($nw,$nh);
422 2
        imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $nw, $nh, $w, $h);//resizing the image
423 2
        imagejpeg($dst_img,$outputfile,80);
424 2
        imagedestroy($src_img);
425 2
        imagedestroy($dst_img);
426
427 2
        return true;
428
    }
429
430 44
    public function getLinkArray ()
431
    {
432 44
        $linkArray = array();
433
434 44
        if ($this->hasCover)
435
        {
436 18
            array_push($linkArray, Data::getLink($this, 'jpg', 'image/jpeg', Link::OPDS_IMAGE_TYPE, 'cover.jpg', NULL));
437
438 18
            array_push($linkArray, Data::getLink($this, 'jpg', 'image/jpeg', Link::OPDS_THUMBNAIL_TYPE, 'cover.jpg', NULL));
439
        }
440
441 44
        foreach ($this->getDatas() as $data)
442
        {
443 44
            if ($data->isKnownType())
444
            {
445 44
                array_push($linkArray, $data->getDataLink(Link::OPDS_ACQUISITION_TYPE, $data->format));
446
            }
447
        }
448
449 44
        foreach ($this->getAuthors() as $author) {
450
            /* @var $author Author */
451 44
            array_push($linkArray, new LinkNavigation($author->getUri(), 'related', str_format(localize('bookentry.author'), localize('splitByLetter.book.other'), $author->name)));
452
        }
453
454 44
        $serie = $this->getSerie();
455 44
        if (!is_null ($serie)) {
456 41
            array_push($linkArray, new LinkNavigation($serie->getUri(), 'related', str_format(localize('content.series.data'), $this->seriesIndex, $serie->name)));
457
        }
458
459 44
        return $linkArray;
460
    }
461
462
463 41
    public function getEntry() {
464 41
        return new EntryBook($this->getTitle(), $this->getEntryId(),
465 41
            $this->getComment(), 'text/html',
466 41
            $this->getLinkArray(), $this);
467
    }
468
469 3
    public static function getBookCount($database = NULL) {
470 3
        return parent::executeQuerySingle('select count(*) from books', $database);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (executeQuerySingle() instead of getBookCount()). Are you sure this is correct? If so, you might want to change this to $this->executeQuerySingle().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
471
    }
472
473 21
    public static function getCount() {
474 21
        global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
475 21
        $nBooks = parent::executeQuerySingle('select count(*) from books');
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (executeQuerySingle() instead of getCount()). Are you sure this is correct? If so, you might want to change this to $this->executeQuerySingle().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
476 21
        $result = array();
477 21
        $entry = new Entry(localize('allbooks.title'),
478 21
                          self::ALL_BOOKS_ID,
479 21
                          str_format(localize('allbooks.alphabetical', $nBooks), $nBooks), 'text',
480 21
                          array(new LinkNavigation('?page='.parent::PAGE_ALL_BOOKS)), '', $nBooks);
481 21
        array_push($result, $entry);
482 21
        if ($config['cops_recentbooks_limit'] > 0) {
483 21
            $entry = new Entry(localize('recent.title'),
484 21
                              self::ALL_RECENT_BOOKS_ID,
485 21
                              str_format(localize('recent.list'), $config['cops_recentbooks_limit']), 'text',
486 21
                              array ( new LinkNavigation ('?page='.parent::PAGE_ALL_RECENT_BOOKS)), '', $config['cops_recentbooks_limit']);
487 21
            array_push($result, $entry);
488
        }
489 21
        return $result;
490
    }
491
492 8
    public static function getBooksByAuthor($authorId, $n) {
493 8
        return self::getEntryArray(self::SQL_BOOKS_BY_AUTHOR, array($authorId), $n);
494
    }
495
496 1
    public static function getBooksByRating($ratingId, $n) {
497 1
        return self::getEntryArray(self::SQL_BOOKS_BY_RATING, array($ratingId), $n);
498
    }
499
500 2
    public static function getBooksByPublisher($publisherId, $n) {
501 2
        return self::getEntryArray(self::SQL_BOOKS_BY_PUBLISHER, array($publisherId), $n);
502
    }
503
504 2
    public static function getBooksBySeries($serieId, $n) {
505 2
        return self::getEntryArray(self::SQL_BOOKS_BY_SERIE, array($serieId), $n);
506
    }
507
508 2
    public static function getBooksByTag($tagId, $n) {
509 2
        return self::getEntryArray(self::SQL_BOOKS_BY_TAG, array($tagId), $n);
510
    }
511
512 2
    public static function getBooksByLanguage($languageId, $n) {
513 2
        return self::getEntryArray(self::SQL_BOOKS_BY_LANGUAGE, array($languageId), $n);
514
    }
515
516
    /**
517
     * @param $customColumn CustomColumn
518
     * @param $id integer
519
     * @param $n integer
520
     * @return array
521
     */
522 4
    public static function getBooksByCustom($customColumn, $id, $n) {
523 4
        list($query, $params) = $customColumn->getQuery($id);
524
525 4
        return self::getEntryArray($query, $params, $n);
526
    }
527
528 37
    public static function getBookById($bookId) {
529 37
        $result = parent::getDb()->prepare('select ' . self::BOOK_COLUMNS . '
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getDb() instead of getBookById()). Are you sure this is correct? If so, you might want to change this to $this->getDb().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
530 37
from books ' . self::SQL_BOOKS_LEFT_JOIN . '
531
where books.id = ?');
532 37
        $result->execute(array($bookId));
533 37
        while ($post = $result->fetchObject())
534
        {
535 36
            $book = new Book($post);
536 36
            return $book;
537
        }
538 1
        return NULL;
539
    }
540
541 1
    public static function getBookByDataId($dataId) {
542 1
        $result = parent::getDb()->prepare('select ' . self::BOOK_COLUMNS . ', data.name, data.format
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getDb() instead of getBookByDataId()). Are you sure this is correct? If so, you might want to change this to $this->getDb().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
543 1
from data, books ' . self::SQL_BOOKS_LEFT_JOIN . '
544
where data.book = books.id and data.id = ?');
545 1
        $result->execute(array($dataId));
546 1
        while ($post = $result->fetchObject())
547
        {
548 1
            $book = new Book($post);
549 1
            $data = new Data($post, $book);
550 1
            $data->id = $dataId;
551 1
            $book->datas = array($data);
552 1
            return $book;
553
        }
554
        return NULL;
555
    }
556
557 2
    public static function getBooksByQuery($query, $n, $database = NULL, $numberPerPage = NULL) {
558 2
        $i = 0;
559 2
        $critArray = array();
560 2
        foreach (array(PageQueryResult::SCOPE_AUTHOR,
561 2
                       PageQueryResult::SCOPE_TAG,
562 2
                       PageQueryResult::SCOPE_SERIES,
563 2
                       PageQueryResult::SCOPE_PUBLISHER,
564 2
                       PageQueryResult::SCOPE_BOOK) as $key) {
565 2
            if (in_array($key, getCurrentOption('ignored_categories')) ||
566 2
                (!array_key_exists($key, $query) && !array_key_exists('all', $query))) {
567
                $critArray[$i] = self::BAD_SEARCH;
568
            }
569
            else {
570 2
                if (array_key_exists($key, $query)) {
571
                    $critArray[$i] = $query[$key];
572
                } else {
573 2
                    $critArray[$i] = $query["all"];
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal all does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
574
                }
575
            }
576 2
            $i++;
577
        }
578 2
        return self::getEntryArray(self::SQL_BOOKS_QUERY, $critArray, $n, $database, $numberPerPage);
579
    }
580
581 1
    public static function getBooks($n) {
582 1
        list ($entryArray, $totalNumber) = self::getEntryArray(self::SQL_BOOKS_ALL , array (), $n);
583 1
        return array($entryArray, $totalNumber);
584
    }
585
586 3 View Code Duplication
    public static function getAllBooks() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
587
        /* @var $result PDOStatement */
588
589 3
        list (, $result) = parent::executeQuery('select {0}
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (executeQuery() instead of getAllBooks()). Are you sure this is correct? If so, you might want to change this to $this->executeQuery().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
590
from books
591
group by substr (upper (sort), 1, 1)
592 3
order by substr (upper (sort), 1, 1)', 'substr (upper (sort), 1, 1) as title, count(*) as count', self::getFilterString(), array(), -1);
593
594 3
        $entryArray = array();
595 3
        while ($post = $result->fetchObject())
596
        {
597 3
            array_push($entryArray, new Entry($post->title, Book::getEntryIdByLetter($post->title),
598 3
                str_format(localize('bookword', $post->count), $post->count), 'text',
599 3
                array(new LinkNavigation('?page='.parent::PAGE_ALL_BOOKS_LETTER.'&id='. rawurlencode($post->title))), '', $post->count));
600
        }
601 3
        return $entryArray;
602
    }
603
604 25
    public static function getBooksByStartingLetter($letter, $n, $database = NULL, $numberPerPage = NULL) {
605 25
        return self::getEntryArray(self::SQL_BOOKS_BY_FIRST_LETTER, array($letter . '%'), $n, $database, $numberPerPage);
606
    }
607
608 55
    public static function getEntryArray($query, $params, $n, $database = NULL, $numberPerPage = NULL) {
609
        /* @var $totalNumber integer */
610
        /* @var $result PDOStatement */
611 55
        list($totalNumber, $result) = parent::executeQuery($query, self::BOOK_COLUMNS, self::getFilterString(), $params, $n, $database, $numberPerPage);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (executeQuery() instead of getEntryArray()). Are you sure this is correct? If so, you might want to change this to $this->executeQuery().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
612
613 55
        $entryArray = array();
614 55
        while ($post = $result->fetchObject())
615
        {
616 41
            $book = new Book($post);
617 41
            array_push($entryArray, $book->getEntry());
618
        }
619 55
        return array($entryArray, $totalNumber);
620
    }
621
622 5
    public static function getAllRecentBooks() {
623 5
        global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
624 5
        list ($entryArray, ) = self::getEntryArray(self::SQL_BOOKS_RECENT . $config['cops_recentbooks_limit'], array(), -1);
625 5
        return $entryArray;
626
    }
627
628
    /**
629
     * The values of all the specified columns
630
     *
631
     * @param string[] $columns
632
     * @return CustomColumn[]
633
     */
634 5
    public function getCustomColumnValues($columns, $asArray = false) {
635 5
        $result = array();
636
637 5
        foreach ($columns as $lookup) {
638 2
            $col = CustomColumnType::createByLookup($lookup);
639 2
            if (!is_null($col)) {
640 2
                $cust = $col->getCustomByBook($this);
641 2
                if (!is_null($cust)) {
642 2
                    if ($asArray) {
643 1
                        array_push($result, $cust->toArray());
644
                    } else {
645 2
                        array_push($result, $cust);
646
                    }
647
                }
648
            }
649
        }
650
651 5
        return $result;
652
    }
653
}
654