<?php
namespace App\Controller;
use App\Entity\Product;
use App\Entity\ProductAction;
use App\Entity\ProductImage;
use App\Form\ProductType;
use App\Repository\ProductActionRepository;
use App\Repository\ProductCategoryRepository;
use App\Repository\ProductRepository;
use App\Service\CoverDesignHelper;
use App\Service\ImageUploader;
use Cocur\Slugify\Slugify;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Mobile_Detect;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Twig\Environment;
class AdminProductController extends AbstractController
{
/**
* @var EntityManagerInterface
*/
private $em;
/**
*
* @var PaginatorInterface
*/
private $paginator;
/**
* @var Environment
*/
private $twig;
/**
* @var Mobile_Detect
*/
private $mobileDetect;
/**
* @var CoverDesignHelper
*/
private $coverDesignHelper;
public function __construct( EntityManagerInterface $em, Environment $twig, PaginatorInterface $paginator, CoverDesignHelper $coverDesignHelper)
{
$this->em = $em;
$this->twig = $twig; // pour ajouter des globals (dispo pour tous les templates)
$this->paginator = $paginator;
$this->coverDesignHelper = $coverDesignHelper;
// MOBILE DETECT
$this->mobileDetect = new Mobile_Detect;
$this->twig->addGlobal('is_mobile', $this->mobileDetect->isMobile());
}
/**
* Listing produits > all products
* @Route("/admin073/catalogue", name="admin_products_index")
* @param ProductRepository $productRepository
* @return Response
*/
public function adminProductsIndex(ProductRepository $productRepository, Request $request)
{
$all_products = $productRepository->findAll(); // grâce au repo, on fait un select de toutes les entrées
$count_all_products = count($all_products);
//dump($products);
// pagination
$products = $this->paginator->paginate($all_products, $request->query->getInt('page', 1), 3);
// filtres : action & catégories
$filters = $this->coverDesignHelper->getFilters();
//dump($filters);
return $this->render('admin/product/index.html.twig', [
'products' => $products,
'filters' => $filters,
'count_all_products' => $count_all_products,
]);
}
/**
* Listing produits filtré : action et catégorie
* par default les filtres sont sur "all" (id = 0)
* @Route("/admin073/catalogue/a/{a_slug}/c/{cat_slug}", name="admin_products_filters")
* @param ProductRepository $productRepository
* @return Response
*/
public function adminProductsFiltres(string $a_slug, string $cat_slug, ProductRepository $productRepository, ProductActionRepository $productActionRepository, ProductCategoryRepository $productCategoryRepository, Request $request)
{
// filtres : action & catégorie
// > ex : /admin073/catalogue/a/maintenir/c/tissu
// > ex : /admin073/catalogue/a/preparer/c/all
// > ex : /admin073/catalogue/a/all/c/tissu
// titre à ajouter au compteur, ex: 8 produits >>> dans "maintenir" et "tissu"
$filter_title['action'] = '';
$filter_title['category'] = '';
// get -> action
if($a_slug != 'all'){
$get_action = $productActionRepository->findOneBy(['slug' => $a_slug]);
dump($get_action);
$action['id'] = $get_action->getId();
$filter_title['action'] = $get_action->getName();
} else {
$action['id'] = 0;
}
// get -> category
if($cat_slug != 'all'){
$get_category = $productCategoryRepository->findOneBy(['slug' => $cat_slug]);
$category['id'] = $get_category->getId();
$filter_title['category'] = $get_category->getName();
} else {
$category['id'] = 0;
}
$get_products = $productRepository->findByActionAndOrCategory($action['id'], $category['id']);
// filtres : action & catégories
$filters = $this->coverDesignHelper->getFilters();
// compteur
$count_all_products = count($get_products);
// pagination
$products = $this->paginator->paginate($get_products, $request->query->getInt('page', 1), 6);
return $this->render('admin/product/index.html.twig', [
'products' => $products,
'filters' => $filters,
'filter_title' => $filter_title,
'count_all_products' => $count_all_products,
]);
}
/**
* Création d'un nouveau produit (product)
* @Route("/admin073/catalogue/new", name="admin_products_new")
*
* @param Request $request
* @param ImageUploader $imageUploader
* @return Response
*/
public function new(request $request, ImageUploader $imageUploader)
{
$product = new Product(); // on crée une entité
// formulaire créé externalisé (dossier /form)
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request); // on passe la requête au formulaire (affichera une entité si elle existe par exemple)
if($form->isSubmitted() && $form->isValid())
{
// on insert d'abord le produit en bdd > last_id récupéré pour nommer le dossier photos du produit
$this->em->persist($product);
$this->em->flush();
$last_product_id = $product->getId();
// gestion des images //////////////////////////////////
// image principale (mainImage)
// https://www.youtube.com/watch?v=apWjiEuDS0k > 15:44
$productMainImage = $form->get('mainImage')->getData();
if($productMainImage){
// upload file (service perso)
$main_image_upload = $imageUploader->upload($productMainImage,$last_product_id);
// enregistrement main image en bdd
$img = new ProductImage();
$img->setName($main_image_upload['name'])
->setSize($main_image_upload['size'])
->setIsMain(1); // main image
$product->addProductImage($img);
// on enregistre la main image du produit
$this->em->persist($product);
$this->em->flush();
}
// galerie d'images
$productImages = $form->get('images')->getData();
dump($productImages);
if($productImages){
foreach($productImages as $image){
// upload file (service perso)
$image_upload = $imageUploader->upload($image,$last_product_id);
// enregistrement chaque image en bdd
$img = new ProductImage();
$img->setName($image_upload['name'])
->setSize($image_upload['size'])
->setIsMain(0);
$product->addProductImage($img);
}
// on enregistre les images du produit
$this->em->persist($product);
$this->em->flush();
}
// On ajoute une notification au user
$this->addFlash(
'success',
"Le produit <strong>{$product->getTitle()}</strong> a bien été enregistré !"
);
// on redirige le user
return $this->redirectToRoute('admin_products_index');
}
return $this->render('admin/product/new.html.twig', [
'product_form' => $form->createView()
]);
}
/**
* Edition d'un produit (product)
* @Route("/admin073/catalogue/{id}/edit", name="admin_products_edit")
*
* @param Product $product
* @param Request $request
* @param ImageUploader $imageUploader
* @return Response
*/
public function edit (Product $product, request $request, ImageUploader $imageUploader)
{
// formulaire créé externalisé (dossier /form)
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request); // on passe la requête au formulaire (affichera une entité si elle existe par exemple)
if($form->isSubmitted() && $form->isValid())
{
// on modifie le produit en bdd
$this->em->persist($product);
$this->em->flush();
$last_product_id = $product->getId();
// gestion des images //////////////////////////////////
// image principale (mainImage)
$productMainImage = $form->get('mainImage')->getData();
if($productMainImage){
// upload file (service perso)
$main_image_upload = $imageUploader->upload($productMainImage,$last_product_id);
// enregistrement main image en bdd
$img = new ProductImage();
$img->setName($main_image_upload['name'])
->setSize($main_image_upload['size'])
->setIsMain(1); // main image
$product->addProductImage($img);
// on enregistre la main image du produit
$this->em->persist($product);
$this->em->flush();
}
// galerie d'images
$productImages = $form->get('images')->getData();
//dump($productImages);
if($productImages){
foreach($productImages as $image){
// upload file (service perso)
$image_upload = $imageUploader->upload($image,$last_product_id);
// enregistrement chaque image en bdd
$img = new ProductImage();
$img->setName($image_upload['name'])
->setSize($image_upload['size'])
->setIsMain(0);
$product->addProductImage($img);
}
// on enregistre les images du produit
$this->em->persist($product);
$this->em->flush();
}
// On ajoute une notification au user
$this->addFlash(
'success',
"Les modifications du produit <strong>{$product->getTitle()}</strong> ont bien été enregistrées !"
);
// on redirige le user
return $this->redirectToRoute('admin_products_index');
}
return $this->render('admin/product/edit.html.twig', [
'product_form' => $form->createView(),
'product' => $product
]);
}
/**
* Suppression d'un produit (en AJAX)
* @Route("/admin073/catalogue/{id}/delete", name="admin_products_delete", methods={"DELETE"})
*
* @param Product $product
* @param Request $request
* @return JsonResponse
*/
public function delete (Product $product, request $request)
{
$data = json_decode($request->getContent(), true);
$product_id = $product->getId();
$product_title = $product->getTitle();
if($this->isCsrfTokenValid('delete'.$product_id, $data['_token']))
{
// delete fichiers images ?
$images = $product->getProductImages();
$product_folder = $this->getParameter('product_images_directory').$product_id;
$empty_product_folder = 0;
if($images){
foreach ($images as $image){
$name = $image->getName();
$file = $product_folder.'/'.$name;
// suppression du fichier dans upload/...
if(is_file($file) && @unlink($file)){
// delete success
} else if (is_file ($file)) {
// unlink failed.
// you would have got an error if it wasn't suppressed
} else {
// file doesn't exist
}
}
// vérif si le dossier est vide
$empty_product_folder = $this->coverDesignHelper->isEmptyDir($product_folder);
if($empty_product_folder){ // is_empty = true
// on kill le dossier de ce produit
if (is_dir($product_folder)) {
$this->coverDesignHelper->rrmdir($product_folder);
}
}
}
// on supprime le produit de la bdd (et relation action, catégorie)
$this->em->remove($product);
$this->em->flush();
// On ajoute une notification au user
$this->addFlash(
'success',
"Le produit <strong>{$product_title}</strong> a été supprimé !"
);
// réponse en json
return new JsonResponse(['success' => 1, 'folder' => $empty_product_folder]);
} else {
// error en json
return new JsonResponse(['error' => 'Token invalide'], 400);
}
}
/**
* Suppression d'une image d'un produit (en AJAX)
* @Route("/admin073/catalogue/delete/image/{id}", name="admin_products_delete_image", methods={"DELETE"})
*
* @param ProductImage $productImage
* @param Request $request
* @return JsonResponse
*/
public function delete_image (ProductImage $productImage, request $request)
{
$data = json_decode($request->getContent(), true);
if($this->isCsrfTokenValid('delete'.$productImage->getId(), $data['_token']))
{
$name = $productImage->getName();
$productId = $productImage->getProduct()->getId();
// suppression du fichier dans upload/...
unlink($this->getParameter('product_images_directory').$productId.'/'.$name);
// suppression de l'image de la bdd
$this->em->remove($productImage);
$this->em->flush();
// réponse en json
return new JsonResponse(['success' => 1]);
} else {
// error en json
return new JsonResponse(['error' => 'Token invalide'], 400);
}
}
/**
* !!!! PAS UTILE !!!
*
* Affichage d'un seul produit (product) (paramConverter est utilisé ici pour convertir le slug en une entité product avec "Product $product")
* @Route("/admin073/catalogue/{slug}", name="admin_products_show")
*
* @return Response
*/
public function show(Product $product)
{
return $this->render('admin/product/show.html.twig', [
'product' => $product
]);
}
}