Open Monograph Press  3.3.0
PublicationService.inc.php
1 <?php
15 namespace APP\Services;
16 
17 use \Application;
18 use \Services;
19 use \PKP\Services\PKPPublicationService;
20 use DAORegistry;
21 
23 
27  public function __construct() {
28  \HookRegistry::register('Publication::getProperties', [$this, 'getPublicationProperties']);
29  \HookRegistry::register('Publication::validate', [$this, 'validatePublication']);
30  \HookRegistry::register('Publication::add', [$this, 'addPublication']);
31  \HookRegistry::register('Publication::edit', [$this, 'editPublication']);
32  \HookRegistry::register('Publication::version', [$this, 'versionPublication']);
33  \HookRegistry::register('Publication::publish::before', [$this, 'publishPublicationBefore']);
34  \HookRegistry::register('Publication::publish', [$this, 'publishPublication']);
35  \HookRegistry::register('Publication::unpublish', [$this, 'unpublishPublication']);
36  \HookRegistry::register('Publication::delete::before', [$this, 'deletePublicationBefore']);
37  }
38 
50  public function getPublicationProperties($hookName, $args) {
51  $values =& $args[0];
52  $publication = $args[1];
53  $props = $args[2];
54  $dependencies = $args[3];
55  $request = $dependencies['request'];
56  $dispatcher = $request->getDispatcher();
57 
58  // Get required submission and context
59  $submission = !empty($args['submission'])
60  ? $args['submission']
61  : $args['submission'] = Services::get('submission')->get($publication->getData('submissionId'));
62 
63  $submissionContext = !empty($dependencies['context'])
64  ? $dependencies['context']
65  : $dependencies['context'] = Services::get('context')->get($submission->getData('contextId'));
66 
67  foreach ($props as $prop) {
68  switch ($prop) {
69  case 'chapters':
70  $values[$prop] = array_map(
71  function($chapter) use ($publication) {
72  $data = $chapter->_data;
73  $data['authors'] = array_map(
74  function($chapterAuthor) {
75  return $chapterAuthor->_data;
76  },
77  DAORegistry::getDAO('ChapterAuthorDAO')->getAuthors($publication->getId(), $chapter->getId())->toArray()
78  );
79  return $data;
80  },
81  $publication->getData('chapters')
82  );
83  break;
84  case 'publicationFormats':
85  $values[$prop] = array_map(
86  function($publicationFormat) {
87  return $publicationFormat->_data;
88  },
89  $publication->getData('publicationFormats')
90  );
91  break;
92  case 'urlPublished':
93  $values[$prop] = $dispatcher->url(
94  $request,
95  ROUTE_PAGE,
96  $submissionContext->getData('urlPath'),
97  'catalog',
98  'book',
99  [$submission->getBestId(), 'version', $publication->getId()]
100  );
101  break;
102  }
103  }
104  }
105 
118  public function validatePublication($hookName, $args) {
119  $errors =& $args[0];
120  $props = $args[2];
121 
122  // Ensure that the specified series exists
123  if (isset($props['seriesId'])) {
124  $series = Application::get()->getSectionDAO()->getById($props['seriesId']);
125  if (!$series) {
126  $errors['seriesId'] = [__('publication.invalidSeries')];
127  }
128  }
129  }
130 
140  public function addPublication($hookName, $args) {
141  $publication = $args[0];
142  $request = $args[1];
143 
144  // Create a thumbnail for the cover image
145  if ($publication->getData('coverImage')) {
146 
147  $submission = Services::get('submission')->get($publication->getData('submissionId'));
148  $submissionContext = $request->getContext();
149  if ($submissionContext->getId() !== $submission->getData('contextId')) {
150  $submissionContext = Services::get('context')->get($submission->getData('contextId'));
151  }
152 
153  $supportedLocales = $submissionContext->getSupportedSubmissionLocales();
154  foreach ($supportedLocales as $localeKey) {
155  if (!array_key_exists($localeKey, $publication->getData('coverImage'))) {
156  continue;
157  }
158 
159  import('classes.file.PublicFileManager');
160  $publicFileManager = new \PublicFileManager();
161  $coverImage = $publication->getData('coverImage', $localeKey);
162  $coverImageFilePath = $publicFileManager->getContextFilesPath($submissionContext->getId()) . '/' . $coverImage['uploadName'];
163  $this->makeThumbnail(
164  $coverImageFilePath,
165  $this->getThumbnailFileName($coverImage['uploadName']),
166  $submissionContext->getData('coverThumbnailsMaxWidth'),
167  $submissionContext->getData('coverThumbnailsMaxHeight')
168  );
169  }
170  }
171  }
172 
184  public function editPublication($hookName, $args) {
185  $newPublication = $args[0];
186  $oldPublication = $args[1];
187  $params = $args[2];
188 
189  // Create or delete the thumbnail of a cover image
190  if (array_key_exists('coverImage', $params)) {
191  import('classes.file.PublicFileManager');
192  $publicFileManager = new \PublicFileManager();
193  $submission = Services::get('submission')->get($newPublication->getData('submissionId'));
194 
195  // Get the submission context
196  $submissionContext = \Application::get()->getRequest()->getContext();
197  if ($submissionContext->getId() !== $submission->getData('contextId')) {
198  $submissionContext = Services::get('context')->get($submission->getData('contextId'));
199  }
200 
201  foreach ($params['coverImage'] as $localeKey => $value) {
202 
203  // Delete the thumbnail if the cover image has been deleted
204  if (is_null($value)) {
205  $oldCoverImage = $oldPublication->getData('coverImage', $localeKey);
206  if (!$oldCoverImage) {
207  continue;
208  }
209 
210  $coverImageFilePath = $publicFileManager->getContextFilesPath($submission->getData('contextId')) . '/' . $oldCoverImage['uploadName'];
211  if (!file_exists($coverImageFilePath)) {
212  $publicFileManager->removeContextFile($submission->getData('contextId'), $this->getThumbnailFileName($oldCoverImage['uploadName']));
213  }
214 
215  // Otherwise generate a new thumbnail if a cover image exists
216  } else {
217  $newCoverImage = $newPublication->getData('coverImage', $localeKey);
218  if (!$newCoverImage) {
219  continue;
220  }
221 
222  $coverImageFilePath = $publicFileManager->getContextFilesPath($submission->getData('contextId')) . '/' . $newCoverImage['uploadName'];
223  $this->makeThumbnail(
224  $coverImageFilePath,
225  $this->getThumbnailFileName($newCoverImage['uploadName']),
226  $submissionContext->getData('coverThumbnailsMaxWidth'),
227  $submissionContext->getData('coverThumbnailsMaxHeight')
228  );
229  }
230  }
231  }
232  }
233 
244  public function versionPublication($hookName, $args) {
245  $newPublication =& $args[0];
246  $oldPublication = $args[1];
247  $request = $args[2];
248 
249  // Publication Formats (and all associated objects)
250  $oldPublicationFormats = $oldPublication->getData('publicationFormats');
251  $newFiles = [];
252  foreach ($oldPublicationFormats as $oldPublicationFormat) {
253  $newPublicationFormat = clone $oldPublicationFormat;
254  $newPublicationFormat->setData('id', null);
255  $newPublicationFormat->setData('publicationId', $newPublication->getId());
256  Application::getRepresentationDAO()->insertObject($newPublicationFormat);
257 
258  // Duplicate publication format metadata
259  $metadataDaos = ['IdentificationCodeDAO', 'MarketDAO', 'PublicationDateDAO', 'SalesRightsDAO'];
260  foreach ($metadataDaos as $metadataDao) {
261  $result = DAORegistry::getDAO($metadataDao)->getByPublicationFormatId($oldPublicationFormat->getId());
262  while (!$result->eof()) {
263  $oldObject = $result->next();
264  $newObject = clone $oldObject;
265  $newObject->setData('id', null);
266  $newObject->setData('publicationFormatId', $newPublicationFormat->getId());
267  DAORegistry::getDAO($metadataDao)->insertObject($newObject);
268  }
269  }
270 
271  // Duplicate publication format files
272  $files = DAORegistry::getDAO('SubmissionFileDAO')->getLatestRevisionsByAssocId(
273  ASSOC_TYPE_REPRESENTATION,
274  $oldPublicationFormat->getId(),
275  $oldPublication->getData('submissionId')
276  );
277  foreach ($files as $file) {
278  $newFile = clone $file;
279  $newFile->setFileId(null);
280  $newFile->setData('assocId', $newPublicationFormat->getId());
281  $newFiles[] = DAORegistry::getDAO('SubmissionFileDAO')->insertObject($newFile, $file->getFilePath());
282 
283  $dependentFiles = DAORegistry::getDAO('SubmissionFileDAO')->getLatestRevisionsByAssocId(
284  ASSOC_TYPE_SUBMISSION_FILE,
285  $file->getFileId(),
286  $file->getData('publicationId')
287  );
288  foreach ($dependentFiles as $dependentFile) {
289  $newDependentFile = clone $dependentFile;
290  $newDependentFile->setFileId(null);
291  DAORegistry::getDAO('SubmissionFileDAO')->insertObject($newDependentFile, $dependentFile->getFilePath());
292  }
293  }
294  }
295 
296  // Chapters (and all associated objects)
297  $oldAuthorsIterator = Services::get('author')->getMany(['publicationIds' => $oldPublication->getId()]);
298  $oldAuthors = iterator_to_array($oldAuthorsIterator);
299  $newAuthorsIterator = Services::get('author')->getMany(['publicationIds' => $newPublication->getId()]);
300  $newAuthors = iterator_to_array($newAuthorsIterator);
301  $result = DAORegistry::getDAO('ChapterDAO')->getByPublicationId($oldPublication->getId());
302  while (!$result->eof()) {
303  $oldChapter = $result->next();
304  $newChapter = clone $oldChapter;
305  $newChapter->setData('id', null);
306  $newChapter->setData('publicationId', $newPublication->getId());
307  $newChapterId = DAORegistry::getDAO('ChapterDAO')->insertChapter($newChapter);
308  $newChapter = DAORegistry::getDAO('ChapterDAO')->getChapter($newChapterId);
309 
310  // Update file chapter associations for new files
311  foreach ($newFiles as $newFile) {
312  if ($newFile->getChapterId() == $oldChapter->getId()) {
313  $newFile->setChapterId($newChapter->getId());
314  DAORegistry::getDAO('SubmissionFileDAO')->updateObject($newFile);
315  }
316  }
317 
318  // We need to link new authors to chapters. To do this, we need a way to
319  // link old authors to the new ones. We use seq property, which should be
320  // unique for each author to determine which new author is a copy of the
321  // old one. We then map the old chapter author associations to the new
322  // authors.
323  $oldChapterAuthors = DAORegistry::getDAO('ChapterAuthorDAO')->getAuthors($oldPublication->getId(), $oldChapter->getId())->toArray();
324  foreach ($newAuthors as $newAuthor) {
325  foreach ($oldAuthors as $oldAuthor) {
326  if ($newAuthor->getData('seq') === $oldAuthor->getData('seq')) {
327  foreach ($oldChapterAuthors as $oldChapterAuthor) {
328  if ($oldChapterAuthor->getId() === $oldAuthor->getId()) {
329  DAORegistry::getDAO('ChapterAuthorDAO')->insertChapterAuthor(
330  $newAuthor->getId(),
331  $newChapter->getId(),
332  $newAuthor->getId() === $newPublication->getData('primaryContactId'),
333  $oldChapterAuthor->getData('seq')
334  );
335  }
336  }
337  }
338  }
339  }
340  }
341 
342  $newPublication = $this->get($newPublication->getId());
343  }
344 
354  public function publishPublicationBefore($hookName, $args) {
355  $newPublication = $args[0];
356  $oldPublication = $args[1];
357 
358  // If the publish date is in the future, set the status to scheduled
359  $datePublished = $oldPublication->getData('datePublished');
360  if ($datePublished && strtotime($datePublished) > strtotime(\Core::getCurrentDate())) {
361  $newPublication->setData('status', STATUS_SCHEDULED);
362  }
363  }
364 
375  public function publishPublication($hookName, $args) {
376  $newPublication = $args[0];
377  $submission = $args[2];
378 
379  // Remove publication format tombstones.
380  $publicationFormats = \DAORegistry::getDAO('PublicationFormatDAO')
381  ->getByPublicationId($newPublication->getId())
382  ->toAssociativeArray();
383  import('classes.publicationFormat.PublicationFormatTombstoneManager');
384  $publicationFormatTombstoneMgr = new \PublicationFormatTombstoneManager();
385  $publicationFormatTombstoneMgr->deleteTombstonesByPublicationFormats($publicationFormats);
386 
387  // Update notification
388  $request = \Application::get()->getRequest();
389  $notificationMgr = new \NotificationManager();
390  $notificationMgr->updateNotification(
391  $request,
392  array(NOTIFICATION_TYPE_APPROVE_SUBMISSION),
393  null,
394  ASSOC_TYPE_MONOGRAPH,
395  $newPublication->getData('submissionId')
396  );
397  }
398 
409  public function unpublishPublication($hookName, $args) {
410  $newPublication = $args[0];
411  $oldPublication = $args[1];
412  $submission = Services::get('submission')->get($newPublication->getData('submissionId'));
413  $submissionContext = Services::get('context')->get($submission->getData('contextId'));
414 
415  // Create tombstones for each publication format.
416  $publicationFormats = \DAORegistry::getDAO('PublicationFormatDAO')
417  ->getByPublicationId($newPublication->getId())
418  ->toAssociativeArray();
419  import('classes.publicationFormat.PublicationFormatTombstoneManager');
420  $publicationFormatTombstoneMgr = new \PublicationFormatTombstoneManager();
421  $publicationFormatTombstoneMgr->insertTombstonesByPublicationFormats($publicationFormats, $submissionContext);
422 
423  // Update notification
424  $request = \Application::get()->getRequest();
425  $notificationMgr = new \NotificationManager();
426  $notificationMgr->updateNotification(
427  $request,
428  array(NOTIFICATION_TYPE_APPROVE_SUBMISSION),
429  null,
430  ASSOC_TYPE_MONOGRAPH,
431  $newPublication->getData('submissionId')
432  );
433  }
434 
443  public function deletePublicationBefore($hookName, $args) {
444  $publication = $args[0];
445  $submission = Services::get('submission')->get($publication->getData('submissionId'));
446  $context = Services::get('context')->get($submission->getData('contextId'));
447 
448  // Publication Formats (and all related objects)
449  $publicationFormats = $publication->getData('publicationFormats');
450  foreach ($publicationFormats as $publicationFormat) {
451  Services::get('publicationFormat')->deleteFormat($publicationFormat, $submission, $context);
452  }
453 
454  // Delete chapters and assigned chapter authors.
455  $chapters = DAORegistry::getDAO('ChapterDAO')->getByPublicationId($publication->getId());
456  while ($chapter = $chapters->next()) {
457  // also removes Chapter Author and file associations
458  DAORegistry::getDAO('ChapterDAO')->deleteObject($chapter);
459  }
460  }
461 
470  public function getThumbnailFileName($fileName) {
471  $pathInfo = pathinfo($fileName);
472  return $pathInfo['filename'] . '_t.' . $pathInfo['extension'];
473  }
474 
482  public function makeThumbnail($filePath, $thumbFileName, $maxWidth, $maxHeight) {
483  $pathParts = pathinfo($filePath);
484 
485  $cover = null;
486  switch ($pathParts['extension']) {
487  case 'jpg': $cover = imagecreatefromjpeg($filePath); break;
488  case 'png': $cover = imagecreatefrompng($filePath); break;
489  case 'gif': $cover = imagecreatefromgif($filePath); break;
490  }
491  if (!isset($cover)) {
492  throw new \Exception('Can not build thumbnail because the file was not found or the file extension was not recognized.');
493  }
494 
495  // Calculate the scaling ratio for each dimension.
496  $originalSizeArray = getimagesize($filePath);
497  $xRatio = min(1, $maxWidth / $originalSizeArray[0]);
498  $yRatio = min(1, $maxHeight / $originalSizeArray[1]);
499 
500  // Choose the smallest ratio and create the target.
501  $ratio = min($xRatio, $yRatio);
502 
503  $thumbWidth = round($ratio * $originalSizeArray[0]);
504  $thumbHeight = round($ratio * $originalSizeArray[1]);
505  $thumb = imagecreatetruecolor($thumbWidth, $thumbHeight);
506  imagecopyresampled($thumb, $cover, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $originalSizeArray[0], $originalSizeArray[1]);
507 
508  switch ($pathParts['extension']) {
509  case 'jpg': imagejpeg($thumb, $pathParts['dirname'] . '/' . $thumbFileName); break;
510  case 'png': imagepng($thumb, $pathParts['dirname'] . '/' . $thumbFileName); break;
511  case 'gif': imagegif($thumb, $pathParts['dirname'] . '/' . $thumbFileName); break;
512  }
513 
514  imagedestroy($thumb);
515  }
516 }
APP\Services\PublicationService\makeThumbnail
makeThumbnail($filePath, $thumbFileName, $maxWidth, $maxHeight)
Definition: PublicationService.inc.php:482
DAORegistry
Maintains a static list of DAO objects so each DAO is instantiated only once.
Definition: DAORegistry.inc.php:20
APP\Services\PublicationService\editPublication
editPublication($hookName, $args)
Definition: PublicationService.inc.php:184
Application\getRepresentationDAO
static getRepresentationDAO()
Definition: Application.inc.php:160
APP\Services\PublicationService
Definition: PublicationService.inc.php:22
APP\Services\PublicationService\versionPublication
versionPublication($hookName, $args)
Definition: PublicationService.inc.php:244
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
PKP\Services\PKPPublicationService
Definition: PKPPublicationService.inc.php:32
APP\Services\PublicationService\validatePublication
validatePublication($hookName, $args)
Definition: PublicationService.inc.php:118
APP\Services
Definition: ContextService.inc.php:15
APP\Services\PublicationService\publishPublication
publishPublication($hookName, $args)
Definition: PublicationService.inc.php:375
Core\getCurrentDate
static getCurrentDate($ts=null)
Definition: Core.inc.php:63
APP\Services\PublicationService\addPublication
addPublication($hookName, $args)
Definition: PublicationService.inc.php:140
HookRegistry\register
static register($hookName, $callback, $hookSequence=HOOK_SEQUENCE_NORMAL)
Definition: HookRegistry.inc.php:70
APP\Services\PublicationService\unpublishPublication
unpublishPublication($hookName, $args)
Definition: PublicationService.inc.php:409
APP\Services\PublicationService\deletePublicationBefore
deletePublicationBefore($hookName, $args)
Definition: PublicationService.inc.php:443
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
APP\Services\PublicationService\getPublicationProperties
getPublicationProperties($hookName, $args)
Definition: PublicationService.inc.php:50
APP\Services\PublicationService\__construct
__construct()
Definition: PublicationService.inc.php:27
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49
APP\Services\PublicationService\getThumbnailFileName
getThumbnailFileName($fileName)
Definition: PublicationService.inc.php:470
APP\Services\PublicationService\publishPublicationBefore
publishPublicationBefore($hookName, $args)
Definition: PublicationService.inc.php:354