<?php
namespace App\Controller;
use App\Dictionary\PageDictionary;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Imagick;
use App\Dictionary\UploaderDirectory;
use App\Entity\Offer;
use App\Entity\Review;
use App\Entity\ReviewAverageRate;
use App\Entity\ReviewComment;
use App\Entity\ReviewCommentAuthor;
use App\Entity\ReviewCommentAuthorDictionary;
use App\Entity\ReviewCommentRate;
use App\Entity\ReviewCommentService;
use App\Entity\ReviewRateDictionary;
use App\Entity\ReviewServiceArea;
use App\Entity\ReviewServiceDictionary;
use App\Entity\ReviewStatusDictionary;
use App\Entity\ReviewVerificationDictionary;
use App\Entity\ReviewVerificationStatusDictionary;
use App\Entity\ReviewVeryfication;
use App\Form\ReviewType;
use App\Repository\OfferRepository;
use App\Service\DirectoryManager;
use App\Uploader\Document;
use App\Entity\ReviewCommentPhoto;
use App\Uploader\FileSaver;
use App\Uploader\HddSaver;
use App\Uploader\ImageResizer;
use App\Validator\ReviewDescription;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* https://www.wanadev.fr/44-tuto-symfony3-et-dropzonejs/
* https://stackoverflow.com/questions/30813413/dropzone-js-and-symfony-formbuilder
*
* Class UploadController
* @package App\Controller
*/
class UploadController extends AbstractController
{
/**
* @var EntityManager|object
*/
private $em;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var ReviewDescription
*/
private $validator;
/**
* @var int ID ogłoszenia
*/
private $offerId;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var bool Własność ustawiana na true w momencie gdy opinia nie przeszła walidacji i musi być sprawdzona pod kątem, np. wulgaryzmów
*/
private $validateChecker = false;
/**
* @var DirectoryManager
*/
private $directoryManager;
/**
* @var ReviewMailerController
*/
private $offerReviewMailer;
/**
* UploadController constructor.
* @param RequestStack $requestStack
* @param EntityManagerInterface $em
* @param ReviewDescription $validator
* @param LoggerInterface $logger
* @param DirectoryManager $directoryManager
* @param ReviewMailerController $offerReviewMailer
*/
public function __construct(RequestStack $requestStack, EntityManagerInterface $em, ReviewDescription $validator, LoggerInterface $logger, DirectoryManager $directoryManager, ReviewMailerController $offerReviewMailer)
{
$this->requestStack = $requestStack;
$this->em = $em;
$this->validator = $validator;
$this->logger = $logger;
$this->directoryManager = $directoryManager;
// $url = explode('/', $this->requestStack->getCurrentRequest()->getPathInfo());
// $this->offerId = (int)end($url);
$this->offerReviewMailer = $offerReviewMailer;
}
/**
* @param Request $request
* @param int $offerId ID ogłoszenia
*
* @return RedirectResponse|Response
*/
public function indexAction(Request $request, int $offerId)
{
$offerBasicData = $this->em->getRepository(Offer::class)->getBasicData($offerId);
/** Jeżeli dane do ogłoszenia nie zostaną odnalezione, ozncza to że nie istnieje */
if (!$offerBasicData) {
throw new NotFoundHttpException('Podane ogłoszenie nie istnieje');
}
$this->setUploadDirectory($offerId);
$this->get('session')->set('offer_id', $offerId);
$form = $this->createForm(ReviewType::class, null, [
'data' => [
'offerId' => $offerId,
'areaId' => $offerBasicData['kategoria_id']
]
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var array Tablica z dodanymi zdjęciami $images */
$images = $this->directoryManager->getFileList(UploaderDirectory::ROOT_DIR . UploaderDirectory::UPLOAD_DIR . DIRECTORY_SEPARATOR . $this->get('session')->get('upload_directory_' . $offerId));
/**
* Zapis danych z formularza do bazy
*/
$offerId = $form->getData()['offerId'];
$offer = $this->em->getRepository(Offer::class)->find($offerId);
$this->saveCommentToDb($offer, $form->getData(), $images);
/**
* Zapis zdjęć na dysku w docelowej lokalizacji
*/
$this->directoryManager->createOfferImageDirectory($offerId);
/** Po udanym zapisie i zwalidowaniu formularza kopiujemy zdjęcia do docelowej lokalizacji */
$this->directoryManager->copyFiles(
$offerId,
$images
);
$this->directoryManager->removeFiles($offerId, true);
/** Wysyłka e-maila po zapisie do bazy jeżeli w opinii nie znaleziono wulgaryzmów lub linków */
if ($this->validateChecker === false) {
$notification = $this->em->getRepository(Offer::class)->checkUserNotification((int)$offerBasicData['uzytkownik_id']);
if ($notification != false) {
$this->offerReviewMailer->sendMailToExhibitorAction($offerBasicData);
}
} else {
$this->offerReviewMailer->sendMailValidatedComment($offerBasicData, $form->getData()['email']);
$this->offerReviewMailer->sendMailToAdmin($offerBasicData);
}
/** Przekierowanie na stronę z widokiem ogłoszenia */
return $this->redirect(PageDictionary::ADRES_STRONY_WWW . '/' . $offerBasicData['link_txt'] . '-' . $offerId . '#opinie');
}
return $this->render('uploader.html.twig', array(
'form' => $form->createView(),
'offer_id' => $offerId,
'offer_basic_data' => $offerBasicData
));
}
/**
* @param Request $request
* @return JsonResponse
*/
public function ajaxSnippetImageSendAction(Request $request)
{
try {
/** @var UploadedFile $media */
$media = $request->files->get('file');
$uploadDir = UploaderDirectory::UPLOAD_DIR . DIRECTORY_SEPARATOR . $this->get('session')->get('upload_directory_' . $this->get('session')->get('offer_id'));
$hddSaver = new HddSaver($media, $this->get('session')->get('offer_id'), $uploadDir);
$hddSaver->save();
/** Tworzenie miniaturki obrazka */
$imageName = $hddSaver->getDocument()->getName();
$hddSaver->resizeImage(
$uploadDir . DIRECTORY_SEPARATOR . $imageName,
$uploadDir . DIRECTORY_SEPARATOR . 'thumb_' . $imageName
);
return new JsonResponse(array('success' => true));
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
return new JsonResponse(array('success' => false));
}
}
/**
* @param int $offerId ID ogłoszenia
*/
private function setUploadDirectory(int $offerId)
{
/**
* Jeżeli został ustawion folder tymczasowy do zapisu musi być on cały czas taki sam
* nawet po przeładowaniu strony
*/
if (!is_null($this->get('session')->get('upload_directory_' . $offerId))) {
return;
}
$date = new \DateTime();
$uploadDir = 'temp_' . $offerId . '_' . $date->format('YmdHis') . '_' . $this->get('session')->getId();
$this->get('session')->set('upload_directory_' . $offerId, $uploadDir);
}
/**
* Zapis do bazy danych z formularza
*
* @param Offer $offer
* @param array $formData Dane pochodzące z formularza
* @param array $images Tablica ze zdjęciami
*/
private function saveCommentToDb(Offer $offer, array $formData, array $images)
{
$reviewStatusDictionary = $this->em->getRepository(ReviewStatusDictionary::class)->find(1);
$reviewAuthorType = $this->em->getRepository(ReviewCommentAuthorDictionary::class)->find($formData['person']);
$review = new Review();
$review->setOffer($offer);
$review->setStatus($reviewStatusDictionary);
$review->setBrowser($_SERVER['HTTP_USER_AGENT']);
$review->setIp($_SERVER['REMOTE_ADDR']);
$this->em->persist($review);
$reviewComment = new ReviewComment();
$reviewComment->setReview($review);
$reviewComment->setCategory($offer->getCategoryId());
$reviewComment->setDescription($formData['description']);
(!is_null($formData['price'])) ? $reviewComment->setPrice(str_replace(',', '.', $formData['price'])) : $formData['price'];
$reviewComment->setSource($formData['portal']);
$this->em->persist($reviewComment);
$reviewAuthor = new ReviewCommentAuthor();
$reviewAuthor->setReviewComment($reviewComment);
$reviewAuthor->setSignature($formData['signature']);
$reviewAuthor->setEmail($formData['email']);
$reviewAuthor->setType($reviewAuthorType);
$this->em->persist($reviewAuthor);
/**
* Dodanie ocen z gwiazdek
*/
if (is_int($formData['stars_quality'])) {
$this->addStarRate($offer, $reviewComment, 2, $formData['stars_quality']);
}
if (is_int($formData['stars_professional'])) {
$this->addStarRate($offer, $reviewComment, 3, $formData['stars_professional']);
}
if (is_int($formData['stars_flexibility'])) {
$this->addStarRate($offer, $reviewComment, 4, $formData['stars_flexibility']);
}
if (is_int($formData['stars_price'])) {
$this->addStarRate($offer, $reviewComment, 5, $formData['stars_price']);
}
if (is_int($formData['stars_cooperation'])) {
$this->addStarRate($offer, $reviewComment, 6, $formData['stars_cooperation']);
}
/** Ocena średnia */
$average = $this->countMainAverageRate($formData);
if ($average) {
$this->addStarRate($offer, $reviewComment, 1, $average);
}
/**
* Zapisanie usług
*/
/** @var ArrayCollection $formData ['service'] */
$services = $formData['service']->toArray();
/** @var ReviewServiceArea $service */
foreach ($services as $service) {
$serviceArea = new ReviewCommentService();
$serviceArea->setReviewComment($reviewComment);
$serviceArea->setService($service->getService());
$this->em->persist($serviceArea);
}
/** Zapis zdjęć do bazy */
$this->savePhoto($images, $reviewComment, $formData['photo_author']);
/** Sprawdzenie treści komentarza pod kątem m.in. wystepowania wulgaryzmów */
if ($this->validator->checkUrlInString($formData['description']) == true || $this->validator->checkBadWords($formData['description']) == true) {
$reviewStatusDictionary = $this->em->getRepository(ReviewStatusDictionary::class)->find(3);
$review->setStatus($reviewStatusDictionary);
$this->em->persist($review);
$reviewVerification = new ReviewVeryfication();
$declarantDictionary = $this->em->getRepository(ReviewVerificationDictionary::class)->find(1);
$verificationStatus = $this->em->getRepository(ReviewVerificationStatusDictionary::class)->find(3);
$reviewVerification->setReview($review);
$reviewVerification->setDeclarant($declarantDictionary);
$reviewVerification->setAddDate(new \DateTime());
$reviewVerification->setDescription('Znaleziono wulgaryzm lub link');
$reviewVerification->setStatus($verificationStatus);
$this->em->persist($reviewVerification);
$this->validateChecker = true;
}
$this->em->flush();
}
/**
* @param Offer $offer
* @param ReviewComment $reviewComment
* @param int $rateDictionaryId ID typu gwiazdki
* @param double $rateValue Ocena
*/
private function addStarRate(Offer $offer, ReviewComment $reviewComment, int $rateDictionaryId, $rateValue)
{
$rateQualityType = $this->em->getRepository(ReviewRateDictionary::class)->find($rateDictionaryId);
$rateQuality = new ReviewCommentRate();
$rateQuality->setReviewComment($reviewComment);
$rateQuality->setType($rateQualityType);
$rateQuality->setRate($rateValue);
$this->em->persist($rateQuality);
/** Dodanie średniej liczby głosów */
/** Sprawdzenie czy istnieje już średnia ocena dla tej oferty i tego typu, jeżeli tak to zostanie pobrana w celu aktualizacji */
$rateQualityAverage = $this->em->getRepository(ReviewAverageRate::class)->findOneBy([
"type" => $rateQualityType,
"offer" => $offer
]);
/** Jeżeli średnia ocena jeszcze nie istnieje dla tego typu oceny to wówczas dodajemy pierwszy wpis */
if (is_null($rateQualityAverage)) {
$rateQualityAverage = new ReviewAverageRate();
}
$voteNumbers = $rateQualityAverage->getVotesNumber() + 1;
$averageRateCount = round($rateQualityAverage->getAverage() * $rateQualityAverage->getVotesNumber(), 2);
$rateQualityAverage->setOffer($offer);
$rateQualityAverage->setType($rateQualityType);
$rateQualityAverage->setAverage(round(($averageRateCount + $rateValue) / $voteNumbers, 2));
$rateQualityAverage->setVotesNumber($voteNumbers);
$this->em->persist($rateQualityAverage);
}
/**
* Metoda wylicza całkowitą średnią z 5 ocen z formularza
*
* @param array $formData
*
* @return bool|float|int
*/
private function countMainAverageRate(array $formData)
{
/**
* W PHP 7.1 jeżeli mamy pusty string to samo zsumowanie spowoduje warning, dlatego trzeba sprawdzić przed dodaniem czy zmienna jest typem numerycznym
*/
$average = 0;
if (is_numeric($formData['stars_quality'])) {
$average += $formData['stars_quality'];
}
if (is_numeric($formData['stars_professional'])) {
$average += $formData['stars_professional'];
}
if (is_numeric($formData['stars_flexibility'])) {
$average += $formData['stars_flexibility'];
}
if (is_numeric($formData['stars_price'])) {
$average += $formData['stars_price'];
}
if (is_numeric($formData['stars_cooperation'])) {
$average += $formData['stars_cooperation'];
}
if (trim($average) !== 0) {
return round($average / 5, 2);
}
return false;
}
/**
* Przygotowanie dodanych zdjęć do zapisu w bazie
*
* @param array $images
* @param ReviewComment $reviewComment
* @param string $photoAuthor
*/
private function savePhoto(array $images, ReviewComment $reviewComment, $photoAuthor)
{
foreach ($images as $image) {
/** Miniatruek nie zapisujemy do bazy, posdiadają one zawsze przedrostke thumb */
if (strpos($image, 'thumb_') === false) {
$photo = new ReviewCommentPhoto();
$photo->setReviewComment($reviewComment);
$photo->setPhotoName($image);
$photo->setAuthor($photoAuthor);
$this->em->persist($photo);
}
}
}
}