Completed
Pull Request — master (#274)
by Markus
05:34
created

Book::getBooksByQuery()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 23
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 18
nc 4
nop 4
dl 0
loc 23
rs 8.5906
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
    public function __construct($line) {
112
        $this->id = $line->id;
113
        $this->title = $line->title;
114
        $this->timestamp = strtotime($line->timestamp);
115
        $this->pubdate = $line->pubdate;
116
        $this->path = Base::getDbDirectory() . $line->path;
117
        $this->relativePath = $line->path;
118
        $this->seriesIndex = $line->series_index;
119
        $this->comment = $line->comment;
120
        $this->uuid = $line->uuid;
121
        $this->hasCover = $line->has_cover;
122
        if (!file_exists($this->getFilePath('jpg'))) {
123
            // double check
124
            $this->hasCover = 0;
125
        }
126
        $this->rating = $line->rating;
127
    }
128
129
    public function getEntryId() {
130
        return self::ALL_BOOKS_UUID.':'.$this->uuid;
131
    }
132
133
    public static function getEntryIdByLetter ($startingLetter) {
134
        return self::ALL_BOOKS_ID.':letter:'.$startingLetter;
135
    }
136
137
    public function getUri () {
138
        return '?page='.parent::PAGE_BOOK_DETAIL.'&id=' . $this->id;
139
    }
140
141
    public function getDetailUrl () {
142
        $urlParam = $this->getUri();
143 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
        return 'index.php' . $urlParam;
145
    }
146
147
    public function getTitle () {
148
        return $this->title;
149
    }
150
151
    /* Other class (author, series, tag, ...) initialization and accessors */
152
153
    /**
154
     * @return Author[]
155
     */
156
    public function getAuthors () {
157
        if (is_null($this->authors)) {
158
            $this->authors = Author::getAuthorByBookId($this->id);
159
        }
160
        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
    public function getPublisher () {
172
        if (is_null($this->publisher)) {
173
            $this->publisher = Publisher::getPublisherByBookId($this->id);
174
        }
175
        return $this->publisher;
176
    }
177
178
    /**
179
     * @return Serie
180
     */
181
    public function getSerie() {
182
        if (is_null($this->serie)) {
183
            $this->serie = Serie::getSerieByBookId($this->id);
184
        }
185
        return $this->serie;
186
    }
187
188
    /**
189
     * @return string
190
     */
191
    public function getLanguages() {
192
        $lang = array();
193
        $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
        $result->execute(array($this->id));
199
        while ($post = $result->fetchObject())
200
        {
201
            array_push($lang, Language::getLanguageString($post->lang_code));
202
        }
203
        return implode(', ', $lang);
204
    }
205
206
    /**
207
     * @return Tag[]
208
     */
209
    public function getTags() {
210
        if (is_null ($this->tags)) {
211
            $this->tags = array();
212
213
            $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
            $result->execute(array($this->id));
219
            while ($post = $result->fetchObject())
220
            {
221
                array_push($this->tags, new Tag($post));
222
            }
223
        }
224
        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
    public function getDatas()
235
    {
236
        if (is_null($this->datas)) {
237
            $this->datas = Data::getDataByBook($this);
238
        }
239
        return $this->datas;
240
    }
241
242
    /* End of other class (author, series, tag, ...) initialization and accessors */
243
244
    public static function getFilterString() {
245
        $filter = getURLParam('tag', NULL);
246
        if (empty($filter)) return '';
247
248
        $exists = true;
249
        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
            $exists = false;
251
            $filter = $matches[1];
252
        }
253
254
        $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
        if (!$exists) {
257
            $result = 'not ' . $result;
258
        }
259
260
        return 'and ' . $result;
261
    }
262
263
    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
        $bestFormatForKindle = array('EPUB', 'PDF', 'AZW3', 'MOBI');
266
        $bestRank = -1;
267
        $bestData = NULL;
268
        foreach ($this->getDatas() as $data) {
269
            $key = array_search($data->format, $bestFormatForKindle);
270
            if ($key !== false && $key > $bestRank) {
271
                $bestRank = $key;
272
                $bestData = $data;
273
            }
274
        }
275
        return $bestData;
276
    }
277
278
    public function getDataById($idData)
279
    {
280
        $reduced = array_filter($this->getDatas(), function ($data) use ($idData) {
281
            return $data->id == $idData;
282
        });
283
        return reset($reduced);
284
    }
285
286
    public function getRating() {
287
        if (is_null($this->rating) || $this->rating == 0) {
288
            return '';
289
        }
290
        $retour = '';
291
        for ($i = 0; $i < $this->rating / 2; $i++) {
292
            $retour .= '&#9733;';
293
        }
294
        for ($i = 0; $i < 5 - $this->rating / 2; $i++) {
295
            $retour .= '&#9734;';
296
        }
297
        return $retour;
298
    }
299
300
    public function getPubDate() {
301
        if (empty ($this->pubdate)) {
302
            return '';
303
        }
304
        $dateY = (int) substr($this->pubdate, 0, 4);
305
        if ($dateY > 102) {
306
            return str_pad($dateY, 4, '0', STR_PAD_LEFT);
307
        }
308
        return '';
309
    }
310
311
    public function getComment($withSerie = true) {
312
        $addition = '';
313
        $se = $this->getSerie ();
314
        if (!is_null ($se) && $withSerie) {
315
            $addition = $addition . '<strong>' . localize('content.series') . '</strong>' . str_format(localize('content.series.data'), $this->seriesIndex, htmlspecialchars($se->name)) . "<br />\n";
316
        }
317
        if (preg_match('/<\/(div|p|a|span)>/', $this->comment))
318
        {
319
            return $addition . html2xhtml($this->comment);
320
        }
321
        else
322
        {
323
            return $addition . htmlspecialchars($this->comment);
324
        }
325
    }
326
327
    public function getDataFormat($format) {
328
        $reduced = array_filter($this->getDatas(), function ($data) use ($format) {
329
            return $data->format == $format;
330
        });
331
        return reset($reduced);
332
    }
333
334
    public function getFilePath($extension, $idData = NULL, $relative = false)
335
    {
336
        if ($extension == 'jpg')
337
        {
338
            $file = 'cover.jpg';
339
        }
340
        else
341
        {
342
            $data = $this->getDataById($idData);
343
            if (!$data) return NULL;
344
            $file = $data->name . '.' . strtolower($data->format);
345
        }
346
347
        if ($relative)
348
        {
349
            return $this->relativePath.'/'.$file;
350
        }
351
        else
352
        {
353
            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
            if ($config['cops_provide_kepub'] == '1'  && preg_match('/Kobo/', $_SERVER['HTTP_USER_AGENT'])) {
383
                $epub->updateForKepub();
384
            }
385
            $epub->download($data->getUpdatedFilenameEpub());
386
        }
387
        catch (Exception $e)
388
        {
389
            echo 'Exception : ' . $e->getMessage();
390
        }
391
    }
392
393
    public function getThumbnail($width, $height, $outputfile = NULL) {
394
        if (is_null($width) && is_null($height)) {
395
            return false;
396
        }
397
398
        $file = $this->getFilePath('jpg');
399
        // get image size
400
        if ($size = GetImageSize($file)) {
401
            $w = $size[0];
402
            $h = $size[1];
403
            //set new size
404
            if (!is_null($width)) {
405
                $nw = $width;
406
                if ($nw >= $w) { return false; }
407
                $nh = ($nw*$h)/$w;
408
            } else {
409
                $nh = $height;
410
                if ($nh >= $h) { return false; }
411
                $nw = ($nh*$w)/$h;
412
            }
413
        } else {
414
            return false;
415
        }
416
417
        //draw the image
418
        $src_img = imagecreatefromjpeg($file);
419
        $dst_img = imagecreatetruecolor($nw,$nh);
420
        imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $nw, $nh, $w, $h);//resizing the image
421
        imagejpeg($dst_img,$outputfile,80);
422
        imagedestroy($src_img);
423
        imagedestroy($dst_img);
424
425
        return true;
426
    }
427
428
    public function getLinkArray ()
429
    {
430
        $linkArray = array();
431
432
        if ($this->hasCover)
433
        {
434
            array_push($linkArray, Data::getLink($this, 'jpg', 'image/jpeg', Link::OPDS_IMAGE_TYPE, 'cover.jpg', NULL));
435
436
            array_push($linkArray, Data::getLink($this, 'jpg', 'image/jpeg', Link::OPDS_THUMBNAIL_TYPE, 'cover.jpg', NULL));
437
        }
438
439
        foreach ($this->getDatas() as $data)
440
        {
441
            if ($data->isKnownType())
442
            {
443
                array_push($linkArray, $data->getDataLink(Link::OPDS_ACQUISITION_TYPE, $data->format));
444
            }
445
        }
446
447
        foreach ($this->getAuthors() as $author) {
448
            /* @var $author Author */
449
            array_push($linkArray, new LinkNavigation($author->getUri(), 'related', str_format(localize('bookentry.author'), localize('splitByLetter.book.other'), $author->name)));
450
        }
451
452
        $serie = $this->getSerie();
453
        if (!is_null ($serie)) {
454
            array_push($linkArray, new LinkNavigation($serie->getUri(), 'related', str_format(localize('content.series.data'), $this->seriesIndex, $serie->name)));
455
        }
456
457
        return $linkArray;
458
    }
459
460
461
    public function getEntry() {
462
        return new EntryBook($this->getTitle(), $this->getEntryId(),
463
            $this->getComment(), 'text/html',
464
            $this->getLinkArray(), $this);
465
    }
466
467
    public static function getBookCount($database = NULL) {
468
        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...
469
    }
470
471
    public static function getCount() {
472
        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...
473
        $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...
474
        $result = array();
475
        $entry = new Entry(localize('allbooks.title'),
476
                          self::ALL_BOOKS_ID,
477
                          str_format(localize('allbooks.alphabetical', $nBooks), $nBooks), 'text',
478
                          array(new LinkNavigation('?page='.parent::PAGE_ALL_BOOKS)), '', $nBooks);
479
        array_push($result, $entry);
480
        if ($config['cops_recentbooks_limit'] > 0) {
481
            $entry = new Entry(localize('recent.title'),
482
                              self::ALL_RECENT_BOOKS_ID,
483
                              str_format(localize('recent.list'), $config['cops_recentbooks_limit']), 'text',
484
                              array ( new LinkNavigation ('?page='.parent::PAGE_ALL_RECENT_BOOKS)), '', $config['cops_recentbooks_limit']);
485
            array_push($result, $entry);
486
        }
487
        return $result;
488
    }
489
490
    public static function getBooksByAuthor($authorId, $n) {
491
        return self::getEntryArray(self::SQL_BOOKS_BY_AUTHOR, array($authorId), $n);
492
    }
493
494
    public static function getBooksByRating($ratingId, $n) {
495
        return self::getEntryArray(self::SQL_BOOKS_BY_RATING, array($ratingId), $n);
496
    }
497
498
    public static function getBooksByPublisher($publisherId, $n) {
499
        return self::getEntryArray(self::SQL_BOOKS_BY_PUBLISHER, array($publisherId), $n);
500
    }
501
502
    public static function getBooksBySeries($serieId, $n) {
503
        return self::getEntryArray(self::SQL_BOOKS_BY_SERIE, array($serieId), $n);
504
    }
505
506
    public static function getBooksByTag($tagId, $n) {
507
        return self::getEntryArray(self::SQL_BOOKS_BY_TAG, array($tagId), $n);
508
    }
509
510
    public static function getBooksByLanguage($languageId, $n) {
511
        return self::getEntryArray(self::SQL_BOOKS_BY_LANGUAGE, array($languageId), $n);
512
    }
513
514
    /**
515
     * @param $customColumn CustomColumn
516
     * @param $id integer
517
     * @param $n integer
518
     * @return array
519
     */
520
    public static function getBooksByCustom($customColumn, $id, $n) {
521
        list($query, $params) = $customColumn->getQuery($id);
522
523
        return self::getEntryArray($query, $params, $n);
524
    }
525
526
    public static function getBookById($bookId) {
527
        $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...
528
from books ' . self::SQL_BOOKS_LEFT_JOIN . '
529
where books.id = ?');
530
        $result->execute(array($bookId));
531
        while ($post = $result->fetchObject())
532
        {
533
            $book = new Book($post);
534
            return $book;
535
        }
536
        return NULL;
537
    }
538
539
    public static function getBookByDataId($dataId) {
540
        $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...
541
from data, books ' . self::SQL_BOOKS_LEFT_JOIN . '
542
where data.book = books.id and data.id = ?');
543
        $result->execute(array($dataId));
544
        while ($post = $result->fetchObject())
545
        {
546
            $book = new Book($post);
547
            $data = new Data($post, $book);
548
            $data->id = $dataId;
549
            $book->datas = array($data);
550
            return $book;
551
        }
552
        return NULL;
553
    }
554
555
    public static function getBooksByQuery($query, $n, $database = NULL, $numberPerPage = NULL) {
556
        $i = 0;
557
        $critArray = array();
558
        foreach (array(PageQueryResult::SCOPE_AUTHOR,
559
                       PageQueryResult::SCOPE_TAG,
560
                       PageQueryResult::SCOPE_SERIES,
561
                       PageQueryResult::SCOPE_PUBLISHER,
562
                       PageQueryResult::SCOPE_BOOK) as $key) {
563
            if (in_array($key, getCurrentOption('ignored_categories')) ||
564
                (!array_key_exists($key, $query) && !array_key_exists('all', $query))) {
565
                $critArray[$i] = self::BAD_SEARCH;
566
            }
567
            else {
568
                if (array_key_exists($key, $query)) {
569
                    $critArray[$i] = $query[$key];
570
                } else {
571
                    $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...
572
                }
573
            }
574
            $i++;
575
        }
576
        return self::getEntryArray(self::SQL_BOOKS_QUERY, $critArray, $n, $database, $numberPerPage);
577
    }
578
579
    public static function getBooks($n) {
580
        list ($entryArray, $totalNumber) = self::getEntryArray(self::SQL_BOOKS_ALL , array (), $n);
581
        return array($entryArray, $totalNumber);
582
    }
583
584 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...
585
        /* @var $result PDOStatement */
586
587
        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...
588
from books
589
group by substr (upper (sort), 1, 1)
590
order by substr (upper (sort), 1, 1)', 'substr (upper (sort), 1, 1) as title, count(*) as count', self::getFilterString(), array(), -1);
591
592
        $entryArray = array();
593
        while ($post = $result->fetchObject())
594
        {
595
            array_push($entryArray, new Entry($post->title, Book::getEntryIdByLetter($post->title),
596
                str_format(localize('bookword', $post->count), $post->count), 'text',
597
                array(new LinkNavigation('?page='.parent::PAGE_ALL_BOOKS_LETTER.'&id='. rawurlencode($post->title))), '', $post->count));
598
        }
599
        return $entryArray;
600
    }
601
602
    public static function getBooksByStartingLetter($letter, $n, $database = NULL, $numberPerPage = NULL) {
603
        return self::getEntryArray(self::SQL_BOOKS_BY_FIRST_LETTER, array($letter . '%'), $n, $database, $numberPerPage);
604
    }
605
606
    public static function getEntryArray($query, $params, $n, $database = NULL, $numberPerPage = NULL) {
607
        /* @var $totalNumber integer */
608
        /* @var $result PDOStatement */
609
        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...
610
611
        $entryArray = array();
612
        while ($post = $result->fetchObject())
613
        {
614
            $book = new Book($post);
615
            array_push($entryArray, $book->getEntry());
616
        }
617
        return array($entryArray, $totalNumber);
618
    }
619
620
    public static function getAllRecentBooks() {
621
        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...
622
        list ($entryArray, ) = self::getEntryArray(self::SQL_BOOKS_RECENT . $config['cops_recentbooks_limit'], array(), -1);
623
        return $entryArray;
624
    }
625
626
    /**
627
     * The values of all the specified columns
628
     *
629
     * @param string[] $columns
630
     * @return CustomColumn[]
631
     */
632
    public function getCustomColumnValues($columns, $asArray = false) {
633
        $result = array();
634
635
        foreach ($columns as $lookup) {
636
            $col = CustomColumnType::createByLookup($lookup);
637
            if (!is_null($col)) {
638
                $cust = $col->getCustomByBook($this);
639
                if (!is_null($cust)) {
640
                    if ($asArray) {
641
                        array_push($result, $cust->toArray());
642
                    } else {
643
                        array_push($result, $cust);
644
                    }
645
                }
646
            }
647
        }
648
649
        return $result;
650
    }
651
}
652