Rev 17050 | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpdeclare(strict_types=1);namespace LeadersLinked\Controller;use Laminas\Db\Adapter\AdapterInterface;use Laminas\Mvc\Controller\AbstractActionController;use Laminas\Log\LoggerInterface;use Laminas\View\Model\ViewModel;use Laminas\View\Model\JsonModel;use LeadersLinked\Library\Functions;use LeadersLinked\Hydrator\ObjectPropertyHydrator;use LeadersLinked\Mapper\DailyPulseEmojiMapper;use LeadersLinked\Form\DailyPulse\DailyPulseAddEmojiForm;use LeadersLinked\Form\DailyPulse\DailyPulseEditEmojiForm;use LeadersLinked\Model\DailyPulseEmoji;use LeadersLinked\Library\Image;use LeadersLinked\Library\Storage;class DailyPulseEmojiController extends AbstractActionController{/**** @var \Laminas\Db\Adapter\AdapterInterface*/private $adapter;/**** @var \LeadersLinked\Cache\CacheInterface*/private $cache;/**** @var \Laminas\Log\LoggerInterface*/private $logger;/**** @var array*/private $config;/**** @var \Laminas\Mvc\I18n\Translator*/private $translator;/**** @param \Laminas\Db\Adapter\AdapterInterface $adapter* @param \LeadersLinked\Cache\CacheInterface $cache* @param \Laminas\Log\LoggerInterface LoggerInterface $logger* @param array $config* @param \Laminas\Mvc\I18n\Translator $translator*/public function __construct($adapter, $cache, $logger, $config, $translator){$this->adapter = $adapter;$this->cache = $cache;$this->logger = $logger;$this->config = $config;$this->translator = $translator;}public function indexAction(){$currentNetworkPlugin = $this->plugin('currentNetworkPlugin');$currentNetwork = $currentNetworkPlugin->getNetwork();$currentUserPlugin = $this->plugin('currentUserPlugin');$currentUser = $currentUserPlugin->getUser();$currentCompany = $currentUserPlugin->getCompany();$request = $this->getRequest();if($request->isGet()) {$headers = $request->getHeaders();$isJson = false;if($headers->has('Accept')) {$accept = $headers->get('Accept');$prioritized = $accept->getPrioritized();foreach($prioritized as $key => $value) {$raw = trim($value->getRaw());if(!$isJson) {$isJson = strpos($raw, 'json');}}}if($isJson) {$search = $this->params()->fromQuery('search', []);$search = empty($search['value']) ? '' : Functions::sanitizeFilterString($search['value']);$page = intval($this->params()->fromQuery('start', 1), 10);$records_x_page = intval($this->params()->fromQuery('length', 10), 10);$order = $this->params()->fromQuery('order', []);$order_field = empty($order[0]['column']) ? 99 : intval($order[0]['column'], 10);$order_direction = empty($order[0]['dir']) ? 'ASC' : strtoupper(Functions::sanitizeFilterString($order[0]['dir']));$fields = ['name'];$order_field = isset($fields[$order_field]) ? $fields[$order_field] : 'name';if(!in_array($order_direction, ['ASC', 'DESC'])) {$order_direction = 'ASC';}$dailyPulseEmojiMapper = DailyPulseEmojiMapper::getInstance($this->adapter);$paginator = $dailyPulseEmojiMapper->fetchAllDataTable($currentCompany->id, $search, $page, $records_x_page, $order_field, $order_direction);$storage = Storage::getInstance($this->config, $this->adapter);$path = $storage->getPathDailyPulse();$items = [];$records = $paginator->getCurrentItems();foreach($records as $record){switch($record->type){case DailyPulseEmoji::TYPE_HOW_ARE_YOU_FEEL :$type = 'LABEL_HOW_ARE_YOU_FEEL';break;case DailyPulseEmoji::TYPE_CLIMATE_ON_YOUR_ORGANIZATION :$type = 'LABEL_CLIMATE_ON_YOUR_ORGANIZATION';break;default :$type = 'LABEL_UNKNOWN';break;}switch($record->status){case DailyPulseEmoji::STATUS_ACTIVE :$status = 'LABEL_ACTIVE';break;case DailyPulseEmoji::STATUS_INACTIVE :$status = 'LABEL_INACTIVE';break;default :$status = 'LABEL_UNKNOWN';break;}$item = ['name' => $record->name,'details' => ['type' => $type,'status' => $status,'order' => $record->order,'points' => $record->points,],'image' => $storage->getGenericImage($path, $record->uuid, $record->image),'actions' => ['link_edit' => $this->url()->fromRoute('daily-pulse/emojis/edit', ['id' => $record->uuid ]),'link_delete' => $this->url()->fromRoute('daily-pulse/emojis/delete', ['id' => $record->uuid ]),]];array_push($items, $item);}return new JsonModel(['success' => true,'data' => ['items' => $items,'total' => $paginator->getTotalItemCount(),]]);} else {$target_size = $this->config['leaderslinked.image_sizes.emoji'];$formAdd = new DailyPulseAddEmojiForm();$formEdit = new DailyPulseEditEmojiForm();$this->layout()->setTemplate('layout/layout-backend');$viewModel = new ViewModel();$viewModel->setTemplate('leaders-linked/daily-pulse/emojis');$viewModel->setVariables(['formAdd' => $formAdd,'formEdit' => $formEdit,'targetSize' => $target_size,]);return $viewModel ;}} else {return new JsonModel(['success' => false,'data' => 'ERROR_METHOD_NOT_ALLOWED']);;}}/*** Agregar un nuevo emoji para el pulso diario** Este método maneja la creación de un nuevo registro de emoji con su imagen asociada.* Valida los datos del formulario, crea el registro del emoji y maneja la carga de la imagen.** @return JsonModel Respuesta con estado de éxito/error y mensaje*/public function addAction(){try {// Validar método de solicitudif (!$this->getRequest()->isPost()) {return $this->createErrorResponse('ERROR_METHOD_NOT_ALLOWED');}// Obtener y validar datos del formulario$formData = $this->getFormData();if (!$formData['isValid']) {return $this->createErrorResponse($formData['messages']);}// Crear y guardar el emoji$emoji = $this->createEmoji($formData['data']);if (!$emoji) {return $this->createErrorResponse('ERROR_CREATING_EMOJI');}// Procesar y guardar la imagenif (!$this->processAndSaveImage($emoji)) {return $this->createErrorResponse('ERROR_UPLOAD_FILE');}// Registrar la acción y retornar éxito$this->logEmojiCreation($emoji);return $this->createSuccessResponse('LABEL_RECORD_ADDED');} catch (\Exception $e) {$this->logger->error('Error al crear emoji: ' . $e->getMessage());return $this->createErrorResponse('ERROR_UNEXPECTED');}}/*** Obtiene y valida los datos del formulario** @return array Datos validados y estado de validación*/private function getFormData(){$form = new DailyPulseAddEmojiForm();$dataPost = array_merge($this->getRequest()->getPost()->toArray(),$this->getRequest()->getFiles()->toArray());$dataPost['status'] = empty($dataPost['status'])? DailyPulseEmoji::STATUS_INACTIVE: $dataPost['status'];$form->setData($dataPost);if ($form->isValid()) {return ['isValid' => true,'data' => (array) $form->getData()];}$messages = [];foreach ((array) $form->getMessages() as $fieldname => $field_messages) {$messages[$fieldname] = array_values($field_messages);}return ['isValid' => false,'messages' => $messages];}/*** Crea un nuevo registro de emoji** @param array $data Datos del emoji* @return DailyPulseEmoji|null Emoji creado o null si falla*/private function createEmoji(array $data){$currentCompany = $this->plugin('currentUserPlugin')->getCompany();$emoji = new DailyPulseEmoji();$emoji->company_id = $currentCompany->id;$emoji->name = $data['name'];$emoji->order = $data['order'];$emoji->points = $data['points'];$emoji->status = $data['status'];$emoji->type = $data['type'];$emoji->image = '';$mapper = DailyPulseEmojiMapper::getInstance($this->adapter);if (!$mapper->insert($emoji)) {return null;}return $mapper->fetchOne($emoji->id);}/*** Procesa y guarda la imagen del emoji** @param DailyPulseEmoji $emoji Emoji al que se le asignará la imagen* @return bool True si la imagen se procesó correctamente*/private function processAndSaveImage(DailyPulseEmoji $emoji){$storage = Storage::getInstance($this->config, $this->adapter);$storage->setFiles($this->getRequest()->getFiles()->toArray());if (!$storage->setCurrentFilename('image')) {return false;}$target_size = $this->config['leaderslinked.image_sizes.emoji'];list($target_width, $target_height) = explode('x', $target_size);$source_filename = $storage->getTmpFilename();$filename = 'emoji-' . uniqid() . '.png';$target_filename = $storage->composePathToFilename(Storage::TYPE_DAILY_PULSE,$emoji->uuid,$filename);if (!$storage->uploadImageCrop($source_filename, $target_filename, $target_width, $target_height)) {return false;}$emoji->image = $filename;return DailyPulseEmojiMapper::getInstance($this->adapter)->update($emoji);}/*** Registra la creación del emoji en el log** @param DailyPulseEmoji $emoji Emoji creado*/private function logEmojiCreation(DailyPulseEmoji $emoji){$currentUser = $this->plugin('currentUserPlugin')->getUser();$this->logger->info('Se agrego el emoji ' . $emoji->name,['user_id' => $currentUser->id,'ip' => Functions::getUserIP()]);}/*** Crea una respuesta de error** @param mixed $message Mensaje de error* @return JsonModel*/private function createErrorResponse($message){return new JsonModel(['success' => false,'data' => $message]);}/*** Crea una respuesta de éxito** @param string $message Mensaje de éxito* @return JsonModel*/private function createSuccessResponse($message){return new JsonModel(['success' => true,'data' => $message]);}/**** Borrar un perfil excepto el público* @return \Laminas\View\Model\JsonModel*/public function deleteAction(){$currentUserPlugin = $this->plugin('currentUserPlugin');$currentUser = $currentUserPlugin->getUser();$currentCompany = $currentUserPlugin->getCompany();$request = $this->getRequest();$id = $this->params()->fromRoute('id');$dailyPulseEmojiMapper = DailyPulseEmojiMapper::getInstance($this->adapter);$dailyPulseEmoji = $dailyPulseEmojiMapper->fetchOneByUuid($id);if(!$dailyPulseEmoji) {return new JsonModel(['success' => false,'data' => 'ERROR_RECORD_NOT_FOUND']);}if($dailyPulseEmoji->company_id != $currentCompany->id) {return new JsonModel(['success' => false,'data' => 'ERROR_UNAUTHORIZED']);}if($request->isPost()) {$result = $dailyPulseEmojiMapper->delete($dailyPulseEmoji);if($result) {$this->logger->info('Se borro el emoji : ' . $dailyPulseEmoji->name, ['user_id' => $currentUser->id, 'ip' => Functions::getUserIP()]);if($dailyPulseEmoji->image) {$storage = Storage::getInstance($this->config, $this->adapter);$target_path = $storage->getPathDailyPulse();$storage->deleteFile($target_path, $dailyPulseEmoji->uuid, $dailyPulseEmoji->image);}$data = ['success' => true,'data' => 'LABEL_RECORD_DELETED'];} else {$data = ['success' => false,'data' => $dailyPulseEmojiMapper->getError()];return new JsonModel($data);}} else {$data = ['success' => false,'data' => 'ERROR_METHOD_NOT_ALLOWED'];return new JsonModel($data);}return new JsonModel($data);}/*** Editar un emoji existente** Este método maneja la actualización de un emoji existente y su imagen asociada.* Valida los datos del formulario, actualiza el registro del emoji y maneja la carga de la imagen.** @return JsonModel Respuesta con estado de éxito/error y mensaje*/public function editAction(){try {$id = $this->params()->fromRoute('id');// Obtener y validar el emoji existente$emoji = $this->getExistingEmoji($id);if (!$emoji) {return $this->createErrorResponse('ERROR_RECORD_NOT_FOUND');}// Validar autorizaciónif (!$this->isAuthorized($emoji)) {return $this->createErrorResponse('ERROR_UNAUTHORIZED');}$request = $this->getRequest();// Manejar solicitud GETif ($request->isGet()) {return $this->getEmojiData($emoji);}// Manejar solicitud POSTif ($request->isPost()) {return $this->updateEmoji($emoji);}return $this->createErrorResponse('ERROR_METHOD_NOT_ALLOWED');} catch (\Exception $e) {$this->logger->error('Error al editar emoji: ' . $e->getMessage());return $this->createErrorResponse('ERROR_UNEXPECTED');}}/*** Obtiene un emoji existente por su UUID** @param string $id UUID del emoji* @return DailyPulseEmoji|null Emoji encontrado o null*/private function getExistingEmoji($id){$mapper = DailyPulseEmojiMapper::getInstance($this->adapter);return $mapper->fetchOneByUuid($id);}/*** Verifica si el usuario está autorizado para editar el emoji** @param DailyPulseEmoji $emoji Emoji a verificar* @return bool True si está autorizado*/private function isAuthorized(DailyPulseEmoji $emoji){$currentCompany = $this->plugin('currentUserPlugin')->getCompany();return $emoji->company_id === $currentCompany->id;}/*** Obtiene los datos del emoji para la vista** @param DailyPulseEmoji $emoji Emoji a obtener datos* @return JsonModel Datos del emoji*/private function getEmojiData(DailyPulseEmoji $emoji){$storage = Storage::getInstance($this->config, $this->adapter);$path = $storage->getPathDailyPulse();return $this->createSuccessResponse(['name' => $emoji->name,'order' => $emoji->order,'status' => $emoji->status,'type' => $emoji->type,'points' => $emoji->points,'image' => $emoji->image ? $storage->getGenericImage($path, $emoji->uuid, $emoji->image) : '']);}/*** Actualiza un emoji existente** @param DailyPulseEmoji $emoji Emoji a actualizar* @return JsonModel Resultado de la actualización*/private function updateEmoji(DailyPulseEmoji $emoji){// Obtener y validar datos del formulario$formData = $this->getEditFormData();if (!$formData['isValid']) {return $this->createErrorResponse($formData['messages']);}// Actualizar datos del emoji$this->updateEmojiData($emoji, $formData['data']);// Procesar imagen si se proporcionó una nuevaif ($this->hasNewImage()) {if (!$this->processAndUpdateImage($emoji)) {return $this->createErrorResponse('ERROR_UPLOAD_FILE');}}// Guardar cambiosif (!$this->saveEmoji($emoji)) {return $this->createErrorResponse('ERROR_UPDATING_EMOJI');}// Registrar la acción$this->logEmojiUpdate($emoji);return $this->createSuccessResponse('LABEL_RECORD_UPDATED');}/*** Obtiene y valida los datos del formulario de edición** @return array Datos validados y estado de validación*/private function getEditFormData(){$form = new DailyPulseEditEmojiForm();$dataPost = array_merge($this->getRequest()->getPost()->toArray(),$this->getRequest()->getFiles()->toArray());$dataPost['status'] = empty($dataPost['status'])? DailyPulseEmoji::STATUS_INACTIVE: $dataPost['status'];$form->setData($dataPost);if ($form->isValid()) {return ['isValid' => true,'data' => (array) $form->getData()];}$messages = [];foreach ((array) $form->getMessages() as $fieldname => $field_messages) {$messages[$fieldname] = array_values($field_messages);}return ['isValid' => false,'messages' => $messages];}/*** Actualiza los datos del emoji con la información del formulario** @param DailyPulseEmoji $emoji Emoji a actualizar* @param array $data Datos del formulario*/private function updateEmojiData(DailyPulseEmoji $emoji, array $data){$emoji->name = $data['name'];$emoji->order = $data['order'];$emoji->points = $data['points'];$emoji->status = $data['status'];$emoji->type = $data['type'];}/*** Verifica si se proporcionó una nueva imagen** @return bool True si hay una nueva imagen*/private function hasNewImage(){$files = $this->getRequest()->getFiles()->toArray();return isset($files['image']) && empty($files['image']['error']);}/*** Procesa y actualiza la imagen del emoji** @param DailyPulseEmoji $emoji Emoji a actualizar* @return bool True si la imagen se procesó correctamente*/private function processAndUpdateImage(DailyPulseEmoji $emoji){$storage = Storage::getInstance($this->config, $this->adapter);$target_path = $storage->getPathDailyPulse();if(!$storage->setCurrentFilename('image')) {return false;}$source_filename = $storage->getTmpFilename();$filename = 'emoji-' . uniqid() . '.png';$target_filename = $storage->composePathToFilename(Storage::TYPE_DAILY_PULSE,$emoji->uuid,$filename);$target_size = $this->config['leaderslinked.image_sizes.emoji'];list($target_width, $target_height) = explode('x', $target_size);$full_tmp_filename = $storage->uploadImageCrop($source_filename,$target_filename,$target_width,$target_height);if (!$full_tmp_filename) {return false;}// Eliminar imagen anterior si existeif ($emoji->image) {$storage->deleteFile($target_path, $emoji->uuid, $emoji->image);}$emoji->image = $filename;return true;}/*** Guarda los cambios del emoji en la base de datos** @param DailyPulseEmoji $emoji Emoji a guardar* @return bool True si se guardó correctamente*/private function saveEmoji(DailyPulseEmoji $emoji){$mapper = DailyPulseEmojiMapper::getInstance($this->adapter);return $mapper->update($emoji);}/*** Registra la actualización del emoji en el log** @param DailyPulseEmoji $emoji Emoji actualizado*/private function logEmojiUpdate(DailyPulseEmoji $emoji){$currentUser = $this->plugin('currentUserPlugin')->getUser();$this->logger->info('Se edito el emoji ' . $emoji->name,['user_id' => $currentUser->id,'ip' => Functions::getUserIP()]);}}