<?php
//src/Service/UserService.php
namespace App\Service;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Forms;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Security;
use Doctrine\Common\Collections\ArrayCollection;
use App\Entity\Product;
use App\Entity\Cart;
use App\Entity\User;
use App\Entity\UserSearch;
use App\Entity\UserViewedProduct;
use App\Entity\UserFavorite;
use App\Entity\Notification;
use App\Entity\RecurringOrder;
use App\Entity\EmailSent;
use App\Entity\UserVariables;
use App\Entity\CompanyAssociation;
use App\Form\ProductType;
use App\Repository\ProductRepository;
use App\Repository\UserRepository;
use Swift_Attachment;
class UserService
{
private $entityInter;
private $em;
private $containerInter;
private $userRepo;
private $mailer;
private $security;
private $session;
private $currentAssociation='none';
public function __construct(EntityManagerInterface $em, ContainerInterface $container, UserRepository $user, Security $security, SessionInterface $session){
//@Legacy
$this->entityInter = $em;
$this->em = $em;
$this->containerInter = $container;
$this->userRepo = $user;
$this->security = $security;
$this->session = $session;
}
/*
* Return the association the user is currently browing in
*/
public function getAssociationUserIsBrowsing()
{
if($this->currentAssociation != 'none')
return $this->currentAssociation;
$var= $this->getVariable('showThisAssociationIdOnly', 'customBrowsing');
if($var){
$this->currentAssociation = $this->em->getRepository(CompanyAssociation::class)->findOneBy(['id' => $var]);
return $this->currentAssociation;
}
return false;
}
public function setAssociationUserIsBrowsing($associationId, $user=false){
$this->setVariable('showThisAssociationIdOnly', $associationId, 'customBrowsing', false, $user);
}
/*
* Get a variable for the user
*/
public function getVariable($name, $category, $user=false, $returnVariable=false)
{
if(!$user)
$user = $this->getUser();
if($user){
$test = $this->em->getRepository(UserVariables::class)->findOneBy(
[
'user' => $user,
'name' => $name,
'category' => $category
]
);
}else{
if(empty($this->session))
$this->session = new Session();
$test = $this->session->get($name.'-'.$category);
if($test)
return $test;
else
return false;
}
if(empty($test) || $test->isExpired())
return false;
else{
if($returnVariable)
return $test;
else
return $test->getValue();
}
}
/*
* Remove a variable for the user
*/
public function delVariable($name, $category, $user=false){
if(!$user)
$user = $this->getUser();
if($user){
$var = $this->getVariable($name, $category, $user, true);
if($var){
$this->em->remove($var);
$this->em->flush();
}
}else{
if(empty($this->session))
$this->session = new Session();
$test = $this->session->remove($name.'-'.$category);
}
}
/*
* Set a variable for the user
*/
public function setVariable($name, $value, $category, $expirationInSeconds=false, $user=false){
if(!$user)
$user = $this->getUser();
if($user){
$test = $this->em->getRepository(UserVariables::class)->findOneBy(
[
'user' => $user,
'name' => $name,
'category' => $category
]
);
if($test){
//Let's renew
if($test->isExpired()){
$test->setDateCreated(new \DateTime());
}
$test->setValue($value);
if($expirationInSeconds)
$test->setDelayInSecondsBeforeExpiration($expirationInSeconds);
$this->em->persist($test);
}else{
$var = new UserVariables();
$var->setName($name);
$var->setValue($value);
$var->setUser($user);
$var->setCategory($category);
if($expirationInSeconds)
$var->setDelayInSecondsBeforeExpiration($expirationInSeconds);
$this->em->persist($var);
}
$this->em->flush();
}else{
if(empty($this->session))
$this->session = new Session();
$this->session->set($name.'-'.$category, $value);
}
return true;
}
/*
* Add Notification to a user
* @TODO move to Notification Service
*/
public function addNotification($type, $title, $message='', $user=false){
$notif = new Notification();
$notif->setTitle($title);
$notif->setText($message);
if(!$user)
$notif->setUser($this->getUser());
else
$notif->setUser($user);
switch($type){
case 'info':
$notif->setIconColor('bg-info');
$notif->setIcon('icon-info');
break;
case 'success':
$notif->setIconColor('bg-success');
$notif->setIcon('icon-like');
break;
case 'warning':
$notif->setIconColor('bg-warning');
$notif->setIcon('icon-star');
break;
case 'error':
$notif->setIconColor('bg-danger');
$notif->setIcon('icon-dislike');
break;
}
$this->entityInter->persist($notif);
$this->entityInter->flush();
}
/*
* Add a Flash message to the user
*/
public function addFlash($type, $message){
$this->session->getFlashBag()->add($type, $message);
}
/*
* Save the search user just did
* Type are either:
* a: All
* p: Product
* c: Company(Store)
*/
public function saveSearch($string, $amount=0, $type='a', $token='', $filters=''){
$user = $this->getUser();
if($user){
$search = new UserSearch();
$search->setUser($user);
$search->setType($type);
$search->setSearch($string);
$search->setAmountResults($amount);
if($type == 'adv'){
$search->setToken($token);
$search->setRawFilters($filters);
}
$this->entityInter->persist($search);
$this->entityInter->flush();
return true;
}else if($type == 'adv'){
$search = new UserSearch();
$search->setType($type);
$search->setSearch($string);
$search->setAmountResults($amount);
if($type == 'adv'){
$search->setToken($token);
$search->setRawFilters($filters);
}
$this->entityInter->persist($search);
$this->entityInter->flush();
return true;
}
return false;
}
/*
* Add the product as viewed
*/
public function addViewedProduct(Product $product){
$user = $this->getUser();
if($user){
$view = new UserViewedProduct();
$view->setUser($user);
$view->setProduct($product);
$this->entityInter->persist($view);
$this->entityInter->flush();
return true;
}
return false;
}
/*
* Send a email to the user
*/
public function sendEmail($subject, $viewHTML=false, $viewTXT=false, $to = false, $from=null, $withCC=false, $replyTo=false){
if ($from==null){
$from = 'reply-message@maturin.ca';
}
try {
//Let's record the email right away in our archive
$log = new EmailSent();
$log->setSentTo($to);
$log->setSentFrom($from);
$log->setSubject($subject);
$tUser = $this->entityInter->getRepository(User::class)->findOneBy(['email' => $to]);
if($tUser)
$log->setUser($tUser);
if($viewHTML)
$log->setBodyHtml($viewHTML);
if($viewTXT)
$log->setBodyText($viewTXT);
$this->em->persist($log);
$this->em->flush();
} catch (\Exception $e) {
// do nothing...
}
if(empty($to)){
$user = $this->getUser();
$to = $user->getEmail();
}
// if ($_ENV['APP_ENV'] != 'prod'){
// $to = $_ENV['DEV_TO_MAIL_ADDRESS'];
// }
$message = (new \Swift_Message($subject))
->setFrom($from)
->setTo($to);
if ($withCC && $_ENV['APP_ENV'] == 'prod')
$message->addCc('info@maturin.ca');
if ($replyTo){
$message->setReplyTo($replyTo);
}
if(!empty($viewHTML)){
$message->setBody($viewHTML, 'text/html');
}
if(!empty($viewTXT)){
$message->setBody($viewTXT, 'text/plain');
}
try {
return MailService::send($message);
} catch (\Throwable $e) {
return false;
} catch (\Exception $e) {
return false;
}
}
public function sendEmailWithAttachement($subject, $viewHTML=false, $viewTXT=false, $to = false, $from=null, $withCC=false, $replyTo=false,$attachment,$invoiceNo){
if ($from==null){
$from = 'reply-message@maturin.ca';
}
//Let's record the email right away in our archive
$log = new EmailSent();
$log->setSentTo($to);
$log->setSentFrom($from);
$log->setSubject($subject);
$tUser = $this->entityInter->getRepository(User::class)->findOneBy(['email' => $to]);
if($tUser)
$log->setUser($tUser);
if($viewHTML)
$log->setBodyHtml($viewHTML);
if($viewTXT)
$log->setBodyText($viewTXT);
$this->em->persist($log);
$this->em->flush();
if(empty($to)){
$user = $this->getUser();
$to = $user->getEmail();
}
if ($_ENV['APP_ENV'] != 'prod')
$to = $_ENV['DEV_TO_MAIL_ADDRESS'];
$filename = sprintf('Facture-%s.pdf', $invoiceNo);
$data = new Swift_Attachment($attachment, $filename, 'application/pdf');
$message = (new \Swift_Message($subject))
->setFrom($from)
->setTo($to)
->attach($data);
if ($withCC && $_ENV['APP_ENV'] == 'prod')
$message->addCc('info@maturin.ca');
if ($replyTo){
$message->setReplyTo($replyTo);
}
if(!empty($viewHTML)){
$message->setBody($viewHTML, 'text/html');
}
if(!empty($viewTXT)){
$message->setBody($viewTXT, 'text/plain');
}
try {
return MailService::send($message);
} catch (\Throwable $e) {
return false;
} catch (\Exception $e) {
return false;
}
}
/*
* Return the user ID
*/
public function getId(){
$user = $this->getUser();
if(is_object($user))
return $user->getId();
else
return false;
//throw new \LogicException('No UserID found while being requested in UserService.php #72.');
}
/*
* Return the user Entity
*/
public function getUser($userId = false){
$user = false;
if(!$userId){
$user = $this->security->getUser();
}else{
if(is_numeric($userId))
$user = $this->entityInter->getRepository(User::class)->find($userId);
elseif(is_string($userId))
$user = $this->entityInter->getRepository(User::class)->findOneByEmail($userId);
else
$user = $userId;
}
return $user;
}
/*
* Return the user FromUserName
*/
public function getUserFromUserName($userName){
$user = $this->entityInter->getRepository(User::class)->findOneBy(
['username' => trim($userName)]
);
return $user;
}
/*
* Return the User Private Contact List
* @TODO right now we return ALL, need to filter this better
*/
public function getContactList($userId = false){
if(!$userId)
$userId = $this->getId();
$users = $this->entityInter->getRepository(User::class)->getRelatedContacts($this->getUser($userId));
return $users;
}
/*
* Promote a user to rank
*/
public function promote($role, User $user = null){
$userManager = $this->containerInter->get('fos_user.user_manager');
$user->addRole($role);
return $userManager->updateUser($user);
}
/*
* demote a user to rank
*/
public function demote($role, User $user = null){
$userManager = $this->containerInter->get('fos_user.user_manager');
$user->removeRole($role);
return $userManager->updateUser($user);
}
/*
* Return the cart
* It store the cart in the cookie for Anonymous users
* Allowing the cart to be transfered to the user once logged in
* This is why cart is called from here and not from Entity
*/
public function getCart(){
if($user = $this->getUser()){
$cart = $this->getUser()->getCart();
}else{
$this->session = new Session();
//Let's build a temporary cart for the user
$cartId = $this->session->get('cartId');
if(!empty($cartId)){
$cart = $this->entityInter->getRepository(Cart::class)->find($cartId);
}else{
$cart = new Cart();
$this->entityInter->persist($cart);
$this->entityInter->flush();
$this->session->set('cartId', $cart->getId());
}
}
return $cart;
}
/*
* Return the cart
* It store the cart in the cookie for Anonymous users
* Allowing the cart to be transfered to the user once logged in
* This is why cart is called from here and not from Entity
*/
public function getFavorites(){
$this->session = new Session();
if($user = $this->getUser()){
//Merge from previous anonymous
/*
if(!empty($this->session->get('favorites'))){
foreach($this->session->get('favorites') as $f){
$product = $this->em->getRepository(Product::class)->findOneBy(['id'=>$f]);
if(!$user->hasFavorite($product)){
$favorite = new UserFavorite();
$favorite->setUser($user);
$favorite->setProduct($product);
$this->em->persist($favorite);
}
}
$this->em->flush();
$this->session->remove('favorites');
}
*/
$favs = $this->getUser()->getFavorites();
}else{
//Let's build a temporary cart for the user
$fav = $this->session->get('favorites');
$favs = new ArrayCollection();
if(!empty($fav)){
foreach($fav as $f){
$t = $this->em->getRepository(Product::class)->findOneBy(['id'=>$f]);
if($t){
$tf = new UserFavorite();
$tf->setProduct($t);
$favs[]=$tf;
}
}
}else{
$this->session->set('favorites', new ArrayCollection());
}
}
return $favs;
}
/*
* Call when a user is login in successfully
* We use this to transfer data from anonymous session to logged one
*/
public function transferSession(User $user){
//Got a cart from when it was not logged yet
//Transfering to right user
$cartId = $this->session->get('cartId');
if(!empty($cartId) && $user){
$cart = $this->entityInter->getRepository(Cart::class)->find($cartId);
if($cart){
//We transfer products to carts
if(!empty($user->getCart())) {
$cartUser = $user->getCart();
foreach($cart->getProducts() as $p) {
$product_isAlreadyInCart = false;
$current_productId = $p->getProduct()->getId();
foreach($cartUser->getProducts() as $up) {
$productId = $up->getProduct()->getId();
if ($productId == $current_productId) {
$product_isAlreadyInCart = true;
$up->setQuantity( $up->getQuantity() + $p->getQuantity() );
$this->entityInter->persist($up);
}
}
if (!$product_isAlreadyInCart) {
$p->setCart($cartUser);
}
$this->entityInter->persist($p);
}
$this->entityInter->persist($cartUser);
//$this->entityInter->remove($cart);
} else {
$user->addCart($cart);
$this->entityInter->persist($user);
$this->entityInter->persist($cart);
}
//$user->removeCart($cartUser);
$this->entityInter->flush();
}
$this->session->remove('cartId');
}
//We transfer the favorites from a anonymous session
$favs = $this->session->get('favorites');
if(!empty($favs) && $user){
foreach($favs as $fav){
$product = $this->em->getRepository(Product::class)->findOneBy(['id'=>$fav]);
if($product){
$favorite = new UserFavorite();
$favorite->setUser($user);
$favorite->setProduct($product);
$this->em->persist($favorite);
}
}
$this->em->flush();
$this->session->remove('favorites');
}
// transfer browsed association
if (($associationId = $this->session->get('showThisAssociationIdOnly-customBrowsing')) != null){
$this->setAssociationUserIsBrowsing($associationId, $user);
}
}
/*
* Tell if user can build bundles
*/
public function isAllowedToMakeBundles(){
if($this->isGod())
return true;
$user = $this->getUser();
if(!$user)
return false;
if($user->isGranted('ROLE_ADMIN_PRODUCT') || $user->isGranted('ROLE_ADMIN_MATURIN'))
return true;
return false;
}
/*
* Tell if the user is a god or not
*/
public function isGod(){
$user = $this->getUser();
if(!$user)
return false;
if($user->isGranted('ROLE_SUPER_ADMIN') || $user->isGranted('ROLE_ADMIN_SYSTEM'))
return true;
else
return false;
}
/*
* Return the actif reccuring orders
*/
public function getActiveRecurringOrders(){
return $this->em->getRepository(RecurringOrder::class)->findActiveOrdersOfUser();
}
/*
* Return products to Suggests
*/
public function findProductsToSuggest($cart=false){
if(!$cart)
$cart = $this->getCart();
$suggestions = array();
$finalProducts = array();
foreach($cart->getProducts() as $p){
$suggestions = array_merge($suggestions, $p->getProduct()->getComplementedByGroups()->toArray());
}
foreach($suggestions as $s){
$finalProducts = array_merge($finalProducts, $s->getComplementaryProducts()->toArray());
}
//Let's remove the beverage for now
$exist = array();
foreach($finalProducts as $k => $p){
if(($p->getUnitDisplay() == 'ml' && $p->getUnitAmount() > 250)|| !$p->isSalable() || isset($exist[$p->getId()])){
unset($finalProducts[$k]);
} elseif (!$this->getAssociationUserIsBrowsing()){
if ($p->getIsDisplayedInAssociationOnly())
unset($finalProducts[$k]);
} elseif (count($p->getPricings()) == 0){
unset($finalProducts[$k]);
} else {
if (!in_array($this->getAssociationUserIsBrowsing()->getId(), $p->getSearchAssociations()))
unset($finalProducts[$k]);
}
$exist[$p->getId()] = true;
}
shuffle($finalProducts);
if(count($finalProducts) > 15){
return array_slice($finalProducts, 0, 15);
}
if(count($finalProducts) < 10){
$extras = $this->em->getRepository(Product::class)->getProductsForUser($this->getUser());
foreach($extras as $key => $p){
if(($p->getUnitDisplay() == 'ml' && $p->getUnitAmount() > 250)|| !$p->isSalable() || isset($exist[$p->getId()])){
unset($extras[$key]);
}
}
return array_merge($finalProducts, $extras);
}
return $finalProducts;
}
}