From b4dcdc4cecedf5187f8140252b872e2625f91559 Mon Sep 17 00:00:00 2001 From: skellamp Date: Tue, 28 Feb 2023 07:33:29 -0500 Subject: [PATCH 01/19] Move Feedback to doctrine --- module/VuFind/config/module.config.php | 1 + .../VuFind/src/VuFind/Db/Entity/Feedback.php | 102 ++++++++++- module/VuFind/src/VuFind/Db/Entity/User.php | 12 +- .../src/VuFind/Db/Service/FeedbackService.php | 158 +++++++++++++++++- .../src/VuFind/Db/Service/PluginManager.php | 6 +- .../src/VuFind/Db/Service/UserService.php | 70 ++++++++ .../src/VuFind/Form/Handler/Database.php | 20 ++- .../VuFind/Form/Handler/DatabaseFactory.php | 4 +- .../Controller/FeedbackController.php | 54 +++--- .../templates/admin/feedback/home.phtml | 34 ++-- 10 files changed, 412 insertions(+), 49 deletions(-) create mode 100644 module/VuFind/src/VuFind/Db/Service/UserService.php diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index fe0150d4993..4e22a120087 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -563,6 +563,7 @@ 'result_cache' => 'filesystem', 'metadata_cache' => 'filesystem', 'hydration_cache' => 'filesystem', + 'proxy_dir' => LOCAL_CACHE_DIR . '/doctrine-proxies', ], ], 'driver' => [ diff --git a/module/VuFind/src/VuFind/Db/Entity/Feedback.php b/module/VuFind/src/VuFind/Db/Entity/Feedback.php index ede7fb06b42..1d4b97fc344 100644 --- a/module/VuFind/src/VuFind/Db/Entity/Feedback.php +++ b/module/VuFind/src/VuFind/Db/Entity/Feedback.php @@ -181,6 +181,16 @@ class Feedback implements EntityInterface */ protected $updatedBy; + /** + * Id getter + * + * @return int + */ + public function getId() + { + return $this->id; + } + /** * Message setter * @@ -194,6 +204,16 @@ public function setMessage(string $message): Feedback return $this; } + /** + * Message getter + * + * @return string + */ + public function getMessage() + { + return $this->message; + } + /** * Form data setter. * @@ -207,6 +227,16 @@ public function setFormData(string $data): Feedback return $this; } + /** + * Form data getter + * + * @return string + */ + public function getFormData() + { + return $this->formData; + } + /** * Form name setter. * @@ -220,6 +250,16 @@ public function setFormName(string $name): Feedback return $this; } + /** + * Form name getter + * + * @return string + */ + public function getFormName() + { + return $this->formName; + } + /** * Created setter. * @@ -233,6 +273,16 @@ public function setCreated(DateTime $dateTime): Feedback return $this; } + /** + * Created getter + * + * @return Datetime + */ + public function getCreated() + { + return $this->created; + } + /** * Updated setter. * @@ -246,6 +296,16 @@ public function setUpdated(DateTime $dateTime): Feedback return $this; } + /** + * Updated getter + * + * @return Datetime + */ + public function getUpdated() + { + return $this->updated; + } + /** * Status setter. * @@ -259,6 +319,16 @@ public function setStatus(string $status): Feedback return $this; } + /** + * Status getter + * + * @return string + */ + public function getStatus() + { + return $this->status; + } + /** * Site URL setter. * @@ -272,6 +342,16 @@ public function setSiteUrl(string $url): Feedback return $this; } + /** + * Site URL getter + * + * @return string + */ + public function getSiteUrl() + { + return $this->siteUrl; + } + /** * User setter. * @@ -285,6 +365,16 @@ public function setUser(?User $user): Feedback return $this; } + /** + * User getter + * + * @return User + */ + public function getUser() + { + return $this->user; + } + /** * Updatedby setter. * @@ -297,4 +387,14 @@ public function setUpdatedBy(?User $user): Feedback $this->updatedBy = $user; return $this; } -} + + /** + * Updatedby getter + * + * @return User + */ + public function getUpdatedBy() + { + return $this->updatedBy; + } +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Db/Entity/User.php b/module/VuFind/src/VuFind/Db/Entity/User.php index 5ce2d9e81b0..86400a9160f 100644 --- a/module/VuFind/src/VuFind/Db/Entity/User.php +++ b/module/VuFind/src/VuFind/Db/Entity/User.php @@ -256,4 +256,14 @@ class User implements EntityInterface * @ORM\Column(name="last_language", type="string", length=30, nullable=false) */ protected $lastLanguage = ''; -} + + /** + * Id getter + * + * @return int + */ + public function getId() + { + return $this->id; + } +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Db/Service/FeedbackService.php b/module/VuFind/src/VuFind/Db/Service/FeedbackService.php index e6ae74a1d96..77ec321058f 100644 --- a/module/VuFind/src/VuFind/Db/Service/FeedbackService.php +++ b/module/VuFind/src/VuFind/Db/Service/FeedbackService.php @@ -4,7 +4,7 @@ * * PHP version 7 * - * Copyright (C) Villanova University 2022. + * Copyright (C) Villanova University 2023. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -21,13 +21,16 @@ * * @category VuFind * @package Database - * @author Demian Katz + * @author Sudharma Kellampalli * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org/wiki/development:plugins:database_gateways Wiki */ namespace VuFind\Db\Service; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Tools\Pagination\Paginator; use VuFind\Db\Entity\Feedback; +use VuFind\Db\Entity\PluginManager as EntityPluginManager; /** * Database service for feedback. @@ -40,6 +43,19 @@ */ class FeedbackService extends AbstractService { + /** + * Constructor + * + * @param EntityManager $entityManager Doctrine ORM entity manager + * @param EntityPluginManager $entityPluginManager VuFind entity plugin manager + */ + public function __construct( + EntityManager $entityManager, + EntityPluginManager $entityPluginManager + ) { + parent::__construct($entityManager, $entityPluginManager); + } + /** * Create a feedback entity object. * @@ -50,4 +66,140 @@ public function createEntity(): Feedback $class = $this->getEntityClass(Feedback::class); return new $class; } -} + + /** + * Get feedback by filter + * + * @param string|null $formName Form name + * @param string|null $siteUrl Site URL + * @param string|null $status Current status + * @param int|null $page Current page + * @param int $limit Limit per page + * + * @return Paginator + */ + public function getFeedbackByFilter( + $formName = null, + $siteUrl = null, + $status = null, + $page = null, + $limit = 20 + ): Paginator { + $dql = "SELECT f, CONCAT(u.firstname, ' ', u.lastname) AS user_name, " + . "CONCAT(m.firstname, ' ', m.lastname) AS manager_name " + . "FROM " . $this->getEntityClass(Feedback::class) . " f " + . "LEFT JOIN f.user u " + . "LEFT JOIN f.updatedBy m "; + $parameters = $dqlWhere = []; + + if (null !== $formName) { + $dqlWhere[] = "f.formName = :formName"; + $parameters['formName'] = $formName; + } + if (null !== $siteUrl) { + $dqlWhere[] = "f.siteUrl = :siteUrl"; + $parameters['siteUrl'] = $siteUrl; + } + if (null !== $status) { + $dqlWhere[] = "f.status = :status"; + $parameters['status'] = $status; + } + if (!empty($dqlWhere)) { + $dql .= ' WHERE ' . implode(' AND ', $dqlWhere); + } + $dql .= " ORDER BY f.created DESC"; + $query = $this->entityManager->createQuery($dql); + $query->setParameters($parameters); + + if (null !== $page) { + $query->setMaxResults($limit); + $query->setFirstResult($limit * ($page - 1)); + } + $paginator = new Paginator($query); + $paginator->setUseOutputWalkers(false); + return $paginator; + } + + /** + * Delete feedback by ids + * + * @param array $ids IDs + * + * @return int Count of deleted rows + */ + public function deleteByIdArray(array $ids): int + { + // Do nothing if we have no IDs to delete! + if (empty($ids)) { + return 0; + } + $dql = 'DELETE FROM ' . $this->getEntityClass(Feedback::class) . ' fb ' + . ' WHERE fb.id IN (:ids)'; + $query = $this->entityManager->createQuery($dql); + $query->setParameters(compact('ids')); + $query->execute(); + return count($ids); + } + + /** + * Get values for a column + * + * @param string $column Column name + * + * @return array + */ + public function getColumn(string $column): array + { + $parameters = []; + $dql = "SELECT f.id, f." . $this->mapper($column) + . " FROM " . $this->getEntityClass(Feedback::class) . " f " + . "ORDER BY f." . $this->mapper($column); + $query = $this->entityManager->createQuery($dql); + return $query->getResult(); + } + + /** + * Update a column + * + * @param string $column Column name + * @param mixed $value Column value + * @param int $id id value + * + * @return bool + */ + public function updateColumn($column, $value, $id) + { + $dql = "UPDATE " . $this->getEntityClass(Feedback::class) . " f " + . "SET f." . $this->mapper($column) . " = :value " + . " WHERE f.id = :id"; + $parameters['value'] = $value; + $parameters['id'] = $id; + $query = $this->entityManager->createQuery($dql); + $query->setParameters($parameters); + return $query->execute(); + } + + /** + * Db columnn name to Doctrine entity field mapper + * + * @param string $column Column name + * + * @return string + */ + public function mapper($column) + { + $map = [ + 'form_data' => 'formData', + 'form_name' => 'formName', + 'site_url' => 'siteUrl', + 'user_id' => 'user', + 'updated_by' => 'updatedBy', + 'message' => 'message', + 'created' => 'created', + 'updated' => 'updated', + 'status' => 'status' + ]; + + return $map[$column]; + } +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Db/Service/PluginManager.php b/module/VuFind/src/VuFind/Db/Service/PluginManager.php index 38bd516ccc2..fa9bcbaec38 100644 --- a/module/VuFind/src/VuFind/Db/Service/PluginManager.php +++ b/module/VuFind/src/VuFind/Db/Service/PluginManager.php @@ -4,7 +4,7 @@ * * PHP version 7 * - * Copyright (C) Villanova University 2021. + * Copyright (C) Villanova University 2023. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -46,6 +46,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager protected $aliases = [ 'feedback' => FeedbackService::class, 'tag' => TagService::class, + 'user' => UserService::class, ]; /** @@ -54,6 +55,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager * @var array */ protected $factories = [ + UserService::class => AbstractServiceFactory::class, FeedbackService::class => AbstractServiceFactory::class, TagService::class => TagServiceFactory::class, ]; @@ -68,4 +70,4 @@ protected function getExpectedInterface() { return AbstractService::class; } -} +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Db/Service/UserService.php b/module/VuFind/src/VuFind/Db/Service/UserService.php new file mode 100644 index 00000000000..5f1f408c531 --- /dev/null +++ b/module/VuFind/src/VuFind/Db/Service/UserService.php @@ -0,0 +1,70 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:database_gateways Wiki + */ +namespace VuFind\Db\Service; + +use Doctrine\ORM\EntityManager; +use VuFind\Db\Entity\PluginManager as EntityPluginManager; +use VuFind\Db\Entity\User; + +/** + * Database service for user. + * + * @category VuFind + * @package Database + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:database_gateways Wiki + */ +class UserService extends AbstractService +{ + /** + * Constructor + * + * @param EntityManager $entityManager Doctrine ORM entity manager + * @param EntityPluginManager $entityPluginManager VuFind entity plugin manager + */ + public function __construct( + EntityManager $entityManager, + EntityPluginManager $entityPluginManager + ) { + parent::__construct($entityManager, $entityPluginManager); + } + + /** + * Lookup and return a user. + * + * @param int $id id value + * + * @return User + */ + public function getUserById($id) + { + $user = $this->entityManager->find(\VuFind\Db\Entity\User::class, $id); + return $user; + } +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Form/Handler/Database.php b/module/VuFind/src/VuFind/Form/Handler/Database.php index 3c2904800b0..eafce047a4b 100644 --- a/module/VuFind/src/VuFind/Form/Handler/Database.php +++ b/module/VuFind/src/VuFind/Form/Handler/Database.php @@ -7,6 +7,7 @@ * PHP version 8 * * Copyright (C) Moravian Library 2022. + * Copyright (C) Villanova University 2023. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -52,6 +53,13 @@ class Database implements HandlerInterface, LoggerAwareInterface */ protected $db; + /** + * User database service + * + * @var \VuFind\Db\Service\UserService + */ + protected $us; + /** * Site base url * @@ -63,13 +71,16 @@ class Database implements HandlerInterface, LoggerAwareInterface * Constructor * * @param \VuFind\Db\Service\FeedbackService $db Feedback database service + * @param \VuFind\Db\Service\UserService $us User database service * @param string $baseUrl Site base url */ public function __construct( \VuFind\Db\Service\FeedbackService $db, + \VuFind\Db\Service\UserService $us, string $baseUrl ) { $this->db = $db; + $this->us = $us; $this->baseUrl = $baseUrl; } @@ -89,12 +100,15 @@ public function handle( ): bool { $fields = $form->mapRequestParamsToFieldValues($params->fromPost()); $fields = array_column($fields, 'value', 'name'); - + $userVal = null; + if ($user) { + $userVal = $this->us->getUserById($user->id); + } $formData = $fields; unset($formData['message']); $now = new \DateTime(); $data = $this->db->createEntity() - ->setUser($user) + ->setUser($userVal) ->setMessage($fields['message'] ?? '') ->setFormData(json_encode($formData)) ->setFormName($form->getFormId()) @@ -112,4 +126,4 @@ public function handle( // thrown an exception above. return true; } -} +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Form/Handler/DatabaseFactory.php b/module/VuFind/src/VuFind/Form/Handler/DatabaseFactory.php index a827b877d53..1713c304949 100644 --- a/module/VuFind/src/VuFind/Form/Handler/DatabaseFactory.php +++ b/module/VuFind/src/VuFind/Form/Handler/DatabaseFactory.php @@ -7,6 +7,7 @@ * PHP version 7 * * Copyright (C) Moravian Library 2022. + * Copyright (C) Villanova University 2023. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -75,7 +76,8 @@ public function __invoke( $baseUrl = $serverUrl($router->assemble([], ['name' => 'home'])); return new $requestedName( $dbServiceManager->get(\VuFind\Db\Service\FeedbackService::class), + $dbServiceManager->get(\VuFind\Db\Service\UserService::class), $baseUrl ); } -} +} \ No newline at end of file diff --git a/module/VuFindAdmin/src/VuFindAdmin/Controller/FeedbackController.php b/module/VuFindAdmin/src/VuFindAdmin/Controller/FeedbackController.php index 0afc1347665..d63f74b93c7 100644 --- a/module/VuFindAdmin/src/VuFindAdmin/Controller/FeedbackController.php +++ b/module/VuFindAdmin/src/VuFindAdmin/Controller/FeedbackController.php @@ -6,7 +6,7 @@ * * PHP version 7 * - * Copyright (C) Moravian Library 2022. + * Copyright (C) Moravian Library 2023. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -29,7 +29,8 @@ */ namespace VuFindAdmin\Controller; -use Laminas\Db\Sql\Select; +use Laminas\ServiceManager\ServiceLocatorInterface; +use VuFind\Db\Service\FeedbackService; use VuFind\Db\Table\Feedback; /** @@ -43,6 +44,25 @@ */ class FeedbackController extends AbstractAdmin { + /** + * Feedback service + * + * @var FeedbackService + */ + protected $feedbackService; + + /** + * Constructor + * + * @param ServiceLocatorInterface $sm Service locator + */ + public function __construct(ServiceLocatorInterface $sm) + { + parent::__construct($sm); + $this->feedbackService = $sm->get(\VuFind\Db\Service\PluginManager::class) + ->get(FeedbackService::class); + } + /** * Get the url parameters * @@ -66,15 +86,18 @@ protected function getParam($param, $prioritizePost = false) */ public function homeAction() { - $feedbackTable = $this->getFeedbackTable(); - $feedback = $feedbackTable->getFeedbackByFilter( + $feedback = $this->feedbackService->getFeedbackByFilter( $this->convertFilter($this->getParam('form_name')), $this->convertFilter($this->getParam('site_url')), $this->convertFilter($this->getParam('status')) ); $view = $this->createViewModel( [ - 'feedback' => $feedback, + 'feedback' => new \Laminas\Paginator\Paginator( + new \DoctrineORMModule\Paginator\Adapter\DoctrinePaginator( + $feedback + ) + ), 'statuses' => $this->getStatuses(), 'uniqueForms' => $this->getUniqueColumn('form_name'), 'uniqueSites' => $this->getUniqueColumn('site_url'), @@ -94,7 +117,6 @@ public function homeAction() public function deleteAction() { $confirm = $this->getParam('confirm', true); - $feedbackTable = $this->getFeedbackTable(); $originUrl = $this->url()->fromRoute('admin/feedback'); $formName = $this->getParam('form_name', true); $siteUrl = $this->getParam('site_url', true); @@ -119,7 +141,7 @@ public function deleteAction() if (!$confirm) { return $this->confirmDelete($ids, $originUrl, $newUrl); } - $delete = $feedbackTable->deleteByIdArray($ids); + $delete = $this->feedbackService->deleteByIdArray($ids); if (0 == $delete) { $this->flashMessenger()->addMessage('feedback_delete_failure', 'error'); return $this->redirect()->toUrl($originUrl); @@ -211,12 +233,9 @@ protected function getConfirmDeleteMessages(int $count): array */ public function updateStatusAction() { - $feedbackTable = $this->getFeedbackTable(); $newStatus = $this->getParam('new_status', true); $id = $this->getParam('id', true); - $feedback = $feedbackTable->select(['id' => $id])->current(); - $feedback->status = $newStatus; - $success = $feedback->save(); + $success = $this->feedbackService->updateColumn("status", $newStatus, $id); if ($success) { $this->flashMessenger()->addMessage( 'feedback_status_update_success', @@ -248,7 +267,7 @@ public function updateStatusAction() */ protected function getFeedbackTable(): Feedback { - return $this->getTable(Feedback::class); + return $this->feedbackService->createEntity(); } /** @@ -260,14 +279,7 @@ protected function getFeedbackTable(): Feedback */ protected function getUniqueColumn(string $column): array { - $feedbackTable = $this->getFeedbackTable(); - $feedback = $feedbackTable->select( - function (Select $select) use ($column) { - $select->columns(['id', $column]); - $select->order($column); - } - ); - $feedbackArray = $feedback->toArray(); + $feedbackArray = $this->feedbackService->getColumn($column); return array_unique(array_column($feedbackArray, $column)); } @@ -299,4 +311,4 @@ protected function getStatuses(): array 'closed', ]; } -} +} \ No newline at end of file diff --git a/themes/bootstrap3/templates/admin/feedback/home.phtml b/themes/bootstrap3/templates/admin/feedback/home.phtml index 4f4c3c20ded..c45228bb4cc 100644 --- a/themes/bootstrap3/templates/admin/feedback/home.phtml +++ b/themes/bootstrap3/templates/admin/feedback/home.phtml @@ -72,30 +72,30 @@ $this->headTitle($this->translate('VuFind Administration - Feedback Management') feedback as $feedbackItem): ?> form_data, true); + $data = json_decode($feedbackItem[0]->getFormData(), true); ?> - - - escapeHtml($feedbackItem->form_name)?> + + + escapeHtml($feedbackItem[0]->getFormName())?> - escapeHtml($feedbackItem->site_url)?> + escapeHtml($feedbackItem[0]->getSiteUrl())?> - truncate($feedbackItem->message, 100, '')?> - message)) > 100): ?> - message?> - - + transEsc('Show')?> -