1
|
|
|
<?php namespace App\Controller; |
2
|
|
|
|
3
|
|
|
use App\Entity\BaseWork; |
4
|
|
|
use App\Entity\Book; |
5
|
|
|
use App\Generator\DownloadFile; |
6
|
|
|
use App\Generator\DownloadUrlGenerator; |
7
|
|
|
use App\Legacy\Setup; |
8
|
|
|
use App\Pagination\Pager; |
9
|
|
|
use App\Service\ContentService; |
10
|
|
|
use App\Service\SearchService; |
11
|
|
|
use App\Util\Stringy; |
12
|
|
|
use Doctrine\ORM\NoResultException; |
13
|
|
|
use Symfony\Component\HttpFoundation\Request; |
14
|
|
|
use Symfony\Component\Routing\Annotation\Route; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @Route("/books") |
18
|
|
|
*/ |
19
|
|
|
class BookController extends Controller { |
20
|
|
|
|
21
|
|
|
const PAGE_COUNT_DEFAULT = 30; |
22
|
|
|
const PAGE_COUNT_LIMIT = 300; |
23
|
|
|
|
24
|
|
|
public function indexAction($_format) { |
25
|
|
|
if (in_array($_format, ['html', 'json'])) { |
26
|
|
|
return [ |
27
|
|
|
'categories' => $this->em()->getCategoryRepository()->getAllAsTree(), |
28
|
|
|
]; |
29
|
|
|
} |
30
|
|
|
return []; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
public function listByCategoryIndexAction($_format) { |
34
|
|
|
switch ($_format) { |
35
|
|
|
case 'html': |
36
|
|
|
case 'opds': |
37
|
|
|
return [ |
38
|
|
|
'categories' => $this->em()->getCategoryRepository()->getAll(), |
39
|
|
|
]; |
40
|
|
|
} |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
public function listByAlphaIndexAction() { |
44
|
|
|
return []; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
public function listByCategoryAction(Request $request, $slug, $page) { |
48
|
|
|
$slug = Stringy::slugify($slug); |
49
|
|
|
$bookRepo = $this->em()->getBookRepository(); |
50
|
|
|
$categoryRepo = $this->em()->getCategoryRepository(); |
51
|
|
|
$category = $categoryRepo->findBySlug($slug); |
52
|
|
|
if ($category === null) { |
53
|
|
|
throw $this->createNotFoundException("Няма категория с код $slug."); |
54
|
|
|
} |
55
|
|
|
$limit = min($request->query->get('limit', static::PAGE_COUNT_DEFAULT), static::PAGE_COUNT_LIMIT); |
56
|
|
|
return [ |
57
|
|
|
'category' => $category, |
58
|
|
|
'parents' => array_reverse($categoryRepo->findCategoryAncestors($category)), |
59
|
|
|
'books' => $bookRepo->findByCategory($categoryRepo->getCategoryDescendantIdsWithSelf($category), $page, $limit), |
60
|
|
|
'pager' => new Pager($page, $category->getNrOfBooks(), $limit), |
61
|
|
|
'route_params' => ['slug' => $slug], |
62
|
|
|
]; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
public function listByAlphaAction(Request $request, $letter, $page) { |
66
|
|
|
$bookRepo = $this->em()->getBookRepository(); |
67
|
|
|
$limit = min($request->query->get('limit', static::PAGE_COUNT_DEFAULT), static::PAGE_COUNT_LIMIT); |
68
|
|
|
$prefix = $letter == '-' ? null : $letter; |
69
|
|
|
return [ |
70
|
|
|
'letter' => $letter, |
71
|
|
|
'books' => $bookRepo->findByPrefix($prefix, $page, $limit), |
72
|
|
|
'pager' => new Pager($page, $bookRepo->countByPrefix($prefix), $limit), |
73
|
|
|
'route_params' => ['letter' => $letter], |
74
|
|
|
]; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
public function listWoCoverAction(Request $request, $page) { |
78
|
|
|
$limit = min($request->query->get('limit', static::PAGE_COUNT_DEFAULT), static::PAGE_COUNT_LIMIT); |
79
|
|
|
$bookRepo = $this->em()->getBookRepository(); |
80
|
|
|
return [ |
81
|
|
|
'books' => $bookRepo->findWithMissingCover($page, $limit), |
82
|
|
|
'pager' => new Pager($page, $bookRepo->getCountWithMissingCover(), $limit), |
83
|
|
|
]; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @Route("/wo-biblioman/{page}.{_format}", name="books_wo_biblioman", defaults={"page": 1, "_format": "html"}) |
88
|
|
|
*/ |
89
|
|
|
public function listWoBibliomanAction(Request $request, $page) { |
90
|
|
|
$limit = min($request->query->get('limit', static::PAGE_COUNT_DEFAULT), static::PAGE_COUNT_LIMIT); |
91
|
|
|
$bookRepo = $this->em()->getBookRepository(); |
92
|
|
|
return [ |
93
|
|
|
'books' => $bookRepo->findWithMissingBibliomanId($page, $limit), |
94
|
|
|
'pager' => new Pager($page, $bookRepo->getCountWithMissingBibliomanId(), $limit), |
95
|
|
|
]; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
public function listByIsbnAction($isbn) { |
99
|
|
|
$books = $this->em()->getBookRepository()->findByIsbn($isbn); |
100
|
|
|
if (count($books) == 1) { |
101
|
|
|
return $this->redirectToRoute('book_show', ['id' => $books[0]->getId()]); |
102
|
|
|
} |
103
|
|
|
return [ |
104
|
|
|
'isbn' => $isbn, |
105
|
|
|
'books' => $books, |
106
|
|
|
]; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
public function showAction(Request $request, $id, $_format) { |
110
|
|
|
list($id) = explode('-', $id); // remove optional slug |
111
|
|
|
try { |
112
|
|
|
$book = $this->em()->getBookRepository()->get($id); |
|
|
|
|
113
|
|
|
} catch (NoResultException $e) { |
114
|
|
|
throw $this->createNotFoundException("Няма книга с номер $id."); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
switch ($_format) { |
118
|
|
|
case 'sfb.zip': |
119
|
|
|
case 'txt.zip': |
120
|
|
|
case 'fb2.zip': |
121
|
|
|
case 'epub': |
122
|
|
|
Setup::doSetup($this->container); |
123
|
|
|
return $this->urlRedirect($this->processDownload($book, $_format)); |
124
|
|
|
case 'djvu': |
125
|
|
|
return $this->urlRedirect($this->processDownload($book, $_format)); |
126
|
|
|
case 'pdf': |
127
|
|
|
if ($book->hasCustomPdf()) { |
128
|
|
|
return $this->urlRedirect($this->processDownload($book, $_format)); |
129
|
|
|
} |
130
|
|
|
if ( ! $this->container->getParameter('pdf_download_enabled')) { |
131
|
|
|
throw $this->createNotFoundException("Няма поддръжка на формата PDF."); |
132
|
|
|
} |
133
|
|
|
return $this->urlRedirect($this->generateConverterUrl($this->container->getParameter('pdf_converter_url'), $book)); |
134
|
|
|
case 'mobi': |
135
|
|
|
if ( ! $this->container->getParameter('mobi_download_enabled')) { |
136
|
|
|
throw $this->createNotFoundException("Няма поддръжка на формата MOBI."); |
137
|
|
|
} |
138
|
|
|
return $this->urlRedirect($this->generateConverterUrl($this->container->getParameter('mobi_converter_url'), $book)); |
139
|
|
|
case 'txt': |
140
|
|
|
Setup::doSetup($this->container); |
141
|
|
|
return $this->asText($book->getContentAsTxt()); |
142
|
|
|
case 'fb2': |
143
|
|
|
Setup::doSetup($this->container); |
144
|
|
|
return $this->asText($book->getContentAsFb2(), 'application/xml'); |
145
|
|
|
case 'sfb': |
146
|
|
|
Setup::doSetup($this->container); |
147
|
|
|
return $this->asText($book->getContentAsSfb()); |
148
|
|
|
case 'data': |
149
|
|
|
return $this->asText($book->getDataAsPlain()); |
150
|
|
|
case 'opds': |
151
|
|
|
break; |
152
|
|
|
case 'pic': |
153
|
|
|
Setup::doSetup($this->container); |
154
|
|
|
break; |
155
|
|
|
case 'cover': |
156
|
|
|
return $this->urlRedirect('/'.ContentService::getCover($book->hasCover() ? $book->getId() : 0, $request->get('size', 300))); |
157
|
|
|
case 'html': |
158
|
|
|
default: |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
return [ |
162
|
|
|
'book' => $book, |
163
|
|
|
'authors' => $book->getAuthors(), |
164
|
|
|
'template' => $book->getTemplateAsXhtml(), |
165
|
|
|
'info' => $book->getExtraInfoAsXhtml(), |
166
|
|
|
'js_extra' => ['book'], |
167
|
|
|
]; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
public function searchAction(Request $request, $_format) { |
171
|
|
|
if ($_format == 'osd') { |
172
|
|
|
return []; |
173
|
|
|
} |
174
|
|
|
if ($_format == 'suggest') { |
175
|
|
|
$query = $request->query->get('q'); |
176
|
|
|
$books = $this->findByQuery([ |
177
|
|
|
'text' => $query, |
178
|
|
|
'by' => 'title,subtitle,origTitle', |
179
|
|
|
'match' => 'prefix', |
180
|
|
|
'limit' => self::PAGE_COUNT_LIMIT, |
181
|
|
|
]); |
182
|
|
|
$items = $descs = $urls = []; |
183
|
|
|
foreach ($books as $book) { |
184
|
|
|
$authors = $book->getAuthorNamesString(); |
185
|
|
|
$items[] = $book->getTitle() . ($authors ? " – $authors" : ''); |
186
|
|
|
$descs[] = ''; |
187
|
|
|
$urls[] = $this->generateAbsoluteUrl('book_show', ['id' => $book->getId()]); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
return [$query, $items, $descs, $urls]; |
191
|
|
|
} |
192
|
|
|
$searchService = new SearchService($this->em()); |
193
|
|
|
$query = $searchService->prepareQuery($request, $_format); |
194
|
|
|
if (isset($query['_template'])) { |
195
|
|
|
return $query; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
if (empty($query['by'])) { |
199
|
|
|
$query['by'] = 'title,subtitle,origTitle'; |
200
|
|
|
} |
201
|
|
|
$books = $this->findByQuery($query); |
202
|
|
|
$found = count($books) > 0; |
203
|
|
|
return [ |
204
|
|
|
'query' => $query, |
205
|
|
|
'books' => $books, |
206
|
|
|
'found' => $found, |
207
|
|
|
'_status' => !$found ? 404 : null, |
208
|
|
|
]; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
public function randomAction() { |
212
|
|
|
$id = $this->em()->getBookRepository()->getRandomId(); |
213
|
|
|
|
214
|
|
|
return $this->urlRedirect($this->generateUrl('book_show', ['id' => $id])); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* @param Book $book |
219
|
|
|
* @param string $format |
220
|
|
|
* @return string File URL |
221
|
|
|
*/ |
222
|
|
|
protected function processDownload(Book $book, $format) { |
223
|
|
|
$dlSite = $this->getMirrorServer(); |
224
|
|
|
if ( $dlSite !== false ) { |
225
|
|
|
return "$dlSite/book/{$book->getId()}.$format"; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
$dlFile = new DownloadFile; |
229
|
|
|
switch ($format) { |
230
|
|
|
case 'sfb.zip': |
231
|
|
|
return $this->getWebRoot() . $dlFile->getSfbForBook($book); |
232
|
|
|
case 'txt.zip': |
233
|
|
|
return $this->getWebRoot() . $dlFile->getTxtForBook($book); |
234
|
|
|
case 'fb2.zip': |
235
|
|
|
return $this->getWebRoot() . $dlFile->getFb2ForBook($book); |
236
|
|
|
case 'epub': |
237
|
|
|
return $this->getWebRoot() . $dlFile->getEpubForBook($book); |
238
|
|
|
case 'djvu': |
239
|
|
|
case 'pdf': |
240
|
|
|
return $this->getWebRoot() . $dlFile->getStaticFileForBook($book, $format); |
241
|
|
|
} |
242
|
|
|
throw $this->createNotFoundException("Книгата не е налична във формат {$format}."); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
protected function generateConverterUrl(string $urlTemplate, Book $book): string { |
246
|
|
|
$epubUrl = $this->generateAbsoluteUrl('book_show', ['id' => $book->getId(), '_format' => Book::FORMAT_EPUB]); |
247
|
|
|
return (new DownloadUrlGenerator())->generateConverterUrl($urlTemplate, $epubUrl); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* @param array $query |
252
|
|
|
* @return Book[] |
253
|
|
|
*/ |
254
|
|
|
protected function findByQuery(array $query) { |
255
|
|
|
return $this->em()->getBookRepository()->findByQuery($query); |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|