Browse Source

Gestion des produits (layout new/edit, catégories, persist)

reduction
Guillaume 4 years ago
parent
commit
3071579629
11 changed files with 477 additions and 183 deletions
  1. +0
    -106
      ShopBundle/Controller/Admin/AdminController.php
  2. +264
    -0
      ShopBundle/Controller/Admin/ProductFamilyController.php
  3. +58
    -0
      ShopBundle/Form/ProductFamilyCategoriesType.php
  4. +1
    -1
      ShopBundle/Model/ProductCategory.php
  5. +7
    -3
      ShopBundle/Model/ProductFamily.php
  6. +9
    -0
      ShopBundle/Repository/ProductCategoryRepository.php
  7. +30
    -1
      ShopBundle/Resources/public/css/backend/custom.css
  8. +0
    -72
      ShopBundle/Resources/views/backend/default/edit_productfamily.html.twig
  9. +5
    -0
      ShopBundle/Resources/views/backend/default/productfamily_edit.html.twig
  10. +98
    -0
      ShopBundle/Resources/views/backend/default/productfamily_form.html.twig
  11. +5
    -0
      ShopBundle/Resources/views/backend/default/productfamily_new.html.twig

+ 0
- 106
ShopBundle/Controller/Admin/AdminController.php View File

@@ -156,20 +156,6 @@ class AdminController extends EasyAdminController
parent::persistEntity($entity);
}

public function updateProductFamilyEntity($entity)
{

$prodductFamilyRequest = $this->request->request->get('productfamily');

if ($taxRateId = intval($prodductFamilyRequest['taxRate']) > 0) {
$repo = $this->em->getRepository(TaxRateInterface::class);
$entity->setTaxRate($repo->find($taxRateId));
}

$this->setUpdated($entity);
parent::updateEntity($entity);
}

public function setUpdated($entity)
{

@@ -295,98 +281,6 @@ class AdminController extends EasyAdminController
return $this->executeDynamicMethod('render<EntityName>Template', ['sortable', "@LcShop/backend/default/sortable.html.twig", $parameters]);
}

private $taxRateClass;
private $choicesTaxRateParam;

public function createProductFamilyEntityFormBuilder($entity, $view)
{

$formBuilder = parent::createEntityFormBuilder($entity, $view);


$class = $this->em->getClassMetadata(ProductCategoryInterface::class);
$this->taxRateClass = $this->em->getClassMetadata(TaxRateInterface::class);

//$formBuilder = $this->get('form.factory')->createBuilder(ProductType::class, $entity);*/
$formBuilder->add('price', MoneyType::class, array(
'block_prefix' => 'lc_tax_price',
'attr' => array(
'class' => 'lc-price'
)
));
$formBuilder->add('priceWithTax', MoneyType::class, array(
'attr' => array(
'class' => 'lc-price-with-tax'
),
'required' => false,
'mapped' => false
));


//CHOICE qui permet de sélectionner une taxe
//ça c'est du lourd fais très attention faudra refactorer
$this->getUser()->getMerchant()->getTaxRate();
$choicesTaxRate['TVA valeur par défaut'] = 0;
foreach ($this->em->getRepository($this->taxRateClass->name)->findAll() as $tax) {
$choicesTaxRate[$tax->getTitle()] = $tax->getId();
$this->choicesTaxRateParam[$tax->getId()] = $tax->getValue();
}
//là mon ami je kiffe symfo !!!!!
$this->choicesTaxRateParam[0] = $this->getUser()->getMerchant()->getTaxRate()->getValue();


$formBuilder->add('taxRate', ChoiceType::class, array(
'choices' => $choicesTaxRate,
'mapped' => false,
'choice_attr' => function ($choice, $key, $value) {
return ['data-tax-rate-value' => $this->choicesTaxRateParam[$choice]];
},

));

$formBuilder->add('unit', ChoiceType::class, array(
'choices' => array(
'pièce' => 'piece',
'g' => 'g',
'kg' => 'kg',
'ml' => 'mL',
'l' => 'L'

),
));
$formBuilder->add('behaviorCountStock', ChoiceType::class, array(
'choices' => array(
'Gèrer le stock par déclinaison' => 'by-product',
'Gèrer le stock par produit' => 'by-product-family'
),
'multiple' => false,
'expanded' => true

));
$formBuilder->add('productCategories', EntityType::class, array(
'multiple' => true,
'expanded' => true,
'class' => $class->name,
'query_builder' => function (EntityRepository $repo) {
return $repo->createQueryBuilder('e')
->where('e.parent is NOT NULL')
->andWhere('e.status > 0')
->orderBy('e.status', "DESC");
}
)
);

$formBuilder->add('products', CollectionType::class, array(
'entry_type'=> ProductType::class,
'allow_add'=>true,
'prototype'=> true
)
);

return $formBuilder;
}


public function createEntityFormBuilder($entity, $view)
{


+ 264
- 0
ShopBundle/Controller/Admin/ProductFamilyController.php View File

@@ -0,0 +1,264 @@
<?php

namespace Lc\ShopBundle\Controller\Admin;

use App\Entity\Product;
use Doctrine\ORM\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Event\EasyAdminEvents;
use Lc\ShopBundle\Context\ProductCategoryInterface;
use Lc\ShopBundle\Context\ProductFamilyInterface;
use Lc\ShopBundle\Context\ProductInterface;
use Lc\ShopBundle\Context\TaxRateInterface;
use Lc\ShopBundle\Form\ProductFamilyCategoriesType;
use Lc\ShopBundle\Form\ProductType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\HttpFoundation\Response;

class ProductFamilyController extends AdminController
{

private $taxRateClass;
private $choicesTaxRateParam;

public function createEntityFormBuilder($entity, $view)
{
$formBuilder = parent::createEntityFormBuilder($entity, $view);

$class = $this->em->getClassMetadata(ProductCategoryInterface::class);
$this->taxRateClass = $this->em->getClassMetadata(TaxRateInterface::class);

//$formBuilder = $this->get('form.factory')->createBuilder(ProductType::class, $entity);*/
$formBuilder->add('price', MoneyType::class, array(
'block_prefix' => 'lc_tax_price',
'attr' => array(
'class' => 'lc-price'
)
));
$formBuilder->add('priceWithTax', MoneyType::class, array(
'attr' => array(
'class' => 'lc-price-with-tax'
),
'required' => false,
'mapped' => false
));


//CHOICE qui permet de sélectionner une taxe
//ça c'est du lourd fais très attention faudra refactorer
$this->getUser()->getMerchant()->getTaxRate();
$choicesTaxRate['TVA valeur par défaut'] = 0;
foreach ($this->em->getRepository($this->taxRateClass->name)->findAll() as $tax) {
$choicesTaxRate[$tax->getTitle()] = $tax->getId();
$this->choicesTaxRateParam[$tax->getId()] = $tax->getValue();
}
//là mon ami je kiffe symfo !!!!!
$this->choicesTaxRateParam[0] = $this->getUser()->getMerchant()->getTaxRate()->getValue();


$formBuilder->add('taxRate', ChoiceType::class, array(
'choices' => $choicesTaxRate,
'mapped' => false,
'choice_attr' => function ($choice, $key, $value) {
return ['data-tax-rate-value' => $this->choicesTaxRateParam[$choice]];
},
));

$formBuilder->add('unit', ChoiceType::class, array(
'choices' => array(
'pièce' => 'piece',
'g' => 'g',
'kg' => 'kg',
'ml' => 'mL',
'l' => 'L'

),
));
$formBuilder->add('behaviorCountStock', ChoiceType::class, array(
'choices' => array(
'Gèrer le stock par déclinaison' => 'by-product',
'Gèrer le stock par produit' => 'by-product-family'
),
'multiple' => false,
'expanded' => true
));

$formBuilder->add('productCategories', ProductFamilyCategoriesType::class) ;

$formBuilder->add('products', CollectionType::class, array(
'label' => 'Catégories',
'entry_type' => ProductType::class,
'allow_add' => true,
'prototype' => true
)
);

return $formBuilder;
}

public function updateEntity($entity)
{
$prodductFamilyRequest = $this->request->request->get('productfamily');

if ($taxRateId = intval($prodductFamilyRequest['taxRate']) > 0) {
$repo = $this->em->getRepository(TaxRateInterface::class);
$entity->setTaxRate($repo->find($taxRateId));
}

$this->processCategories($entity) ;
$this->processProducts($entity) ;

$this->setUpdated($entity);

parent::updateEntity($entity);
}

public function persistEntity($entity)
{
$this->processCategories($entity) ;
$this->processProducts($entity) ;

parent::persistEntity($entity) ;
}

protected function processProducts($entity)
{
if(count($entity->getProducts()) == 0) {
$product = new Product();
$product->setTitle($entity->getTitle()) ;
$product->setCreatedBy($this->getUser()) ;
$product->setUpdatedBy($this->getUser()) ;
$this->em->persist($product);

$entity->addProduct($product) ;
}
}

protected function processCategories(ProductFamilyInterface $entity)
{
$productCategoryRepository = $this->getDoctrine()->getRepository(ProductCategoryInterface::class) ;
$productCategories = $entity->getProductCategories() ;

$entity->initProductCategories() ;

foreach($productCategories as $key => $bool) {
if(is_bool($bool) && $bool) {
if(strpos($key, 'category_children_') !== false) {
$idCategory = (int) str_replace('category_children_', '', $key) ;
}
else {
$idCategory = (int) str_replace('category_', '', $key) ;
}

$category = $productCategoryRepository->find($idCategory) ;
$entity->addProductCategory($category) ;
}
}
}
protected function editAction()
{

$this->dispatch(EasyAdminEvents::PRE_EDIT);

$id = $this->request->query->get('id');
$easyadmin = $this->request->attributes->get('easyadmin');
$entity = $easyadmin['item'];

if ($this->request->isXmlHttpRequest() && $property = $this->request->query->get('property')) {
$newValue = 'true' === mb_strtolower($this->request->query->get('newValue'));
$fieldsMetadata = $this->entity['list']['fields'];

if (!isset($fieldsMetadata[$property]) || 'toggle' !== $fieldsMetadata[$property]['dataType']) {
throw new \RuntimeException(sprintf('The type of the "%s" property is not "toggle".', $property));
}

$this->updateEntityProperty($entity, $property, $newValue);

// cast to integer instead of string to avoid sending empty responses for 'false'
return new Response((int) $newValue);
}

$fields = $this->entity['edit']['fields'];

$editForm = $this->executeDynamicMethod('create<EntityName>EditForm', [$entity, $fields]);
$deleteForm = $this->createDeleteForm($this->entity['name'], $id);



$editForm->handleRequest($this->request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->processUploadedFiles($editForm);

$this->dispatch(EasyAdminEvents::PRE_UPDATE, ['entity' => $entity]);
$this->executeDynamicMethod('update<EntityName>Entity', [$entity, $editForm]);
$this->dispatch(EasyAdminEvents::POST_UPDATE, ['entity' => $entity]);

return $this->redirectToReferrer();
}

$this->dispatch(EasyAdminEvents::POST_EDIT);

$productCategoryRepository = $this->getDoctrine()->getRepository(ProductCategoryInterface::class);
$categories = $productCategoryRepository->findAllParents();

$parameters = [
'form' => $editForm->createView(),
'entity_fields' => $fields,
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
'categories' => $categories
];

return $this->executeDynamicMethod('render<EntityName>Template', ['edit', $this->entity['templates']['edit'], $parameters]);
}

protected function newAction()
{
$this->dispatch(EasyAdminEvents::PRE_NEW);

$entity = $this->executeDynamicMethod('createNew<EntityName>Entity');

$easyadmin = $this->request->attributes->get('easyadmin');
$easyadmin['item'] = $entity;
$this->request->attributes->set('easyadmin', $easyadmin);

$fields = $this->entity['new']['fields'];

$newForm = $this->executeDynamicMethod('create<EntityName>NewForm', [$entity, $fields]);

$newForm->handleRequest($this->request);

if ($newForm->isSubmitted() && $newForm->isValid()) {
$this->processUploadedFiles($newForm);

$this->dispatch(EasyAdminEvents::PRE_PERSIST, ['entity' => $entity]);
$this->executeDynamicMethod('persist<EntityName>Entity', [$entity, $newForm]);
$this->dispatch(EasyAdminEvents::POST_PERSIST, ['entity' => $entity]);

return $this->redirectToReferrer();
}

$this->dispatch(EasyAdminEvents::POST_NEW, [
'entity_fields' => $fields,
'form' => $newForm,
'entity' => $entity,
]);


$productCategoryRepository = $this->getDoctrine()->getRepository(ProductCategoryInterface::class);
$categories = $productCategoryRepository->findAllParents();

$parameters = [
'form' => $newForm->createView(),
'entity_fields' => $fields,
'entity' => $entity,
'categories' => $categories,
];

return $this->executeDynamicMethod('render<EntityName>Template', ['new', $this->entity['templates']['new'], $parameters]);
}

}

+ 58
- 0
ShopBundle/Form/ProductFamilyCategoriesType.php View File

@@ -0,0 +1,58 @@
<?php

namespace Lc\ShopBundle\Form;

use Doctrine\ORM\EntityManagerInterface;
use Lc\ShopBundle\Context\ProductCategoryInterface;
use Lc\ShopBundle\Context\ProductInterface;
use Lc\ShopBundle\Repository\ProductCategoryRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ProductFamilyCategoriesType extends AbstractType
{
protected $em;
protected $productCategoryRepository ;

public function __construct(EntityManagerInterface $entityManager, ProductCategoryRepository $productCategoryRepository)
{
$this->em = $entityManager;
$this->productCategoryRepository = $productCategoryRepository ;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
$categories = $this->productCategoryRepository->findAllParents();

$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($categories) {
$builder = $event->getForm();
$currentProductCategories = $event->getData();

foreach ($categories as $category) {
$builder->add('category_' . $category->getId(), CheckboxType::class, [
'label' => $category->getTitle(),
'data' => $currentProductCategories->contains($category),
'required' => false,
]);
foreach ($category->getChildrens() as $children) {
$builder->add('category_children_' . $children->getId(), CheckboxType::class, [
'label' => $children->getTitle(),
'data' => $currentProductCategories->contains($children),
'required' => false,
]);
}
}
});
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
//'data_class' => $this->em->getClassMetadata(ProductInterface::class)->getName(),
]);
}
}

+ 1
- 1
ShopBundle/Model/ProductCategory.php View File

@@ -31,7 +31,7 @@ abstract class ProductCategory extends AbstractDocumentEntity implements TreeInt

public function __construct()
{
$this->productCategories = new ArrayCollection();
$this->childrens = new ArrayCollection();
}



+ 7
- 3
ShopBundle/Model/ProductFamily.php View File

@@ -24,10 +24,9 @@ abstract class ProductFamily extends AbstractDocumentEntity
protected $productCategories;

/**
* @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="productFamily", orphanRemoval=true)
* @ORM\OneToMany(targetEntity="Lc\ShopBundle\Context\ProductInterface", mappedBy="productFamily", orphanRemoval=true)
*/
private $products;

protected $products;

/**
* @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\TaxRateInterface")
@@ -132,6 +131,11 @@ abstract class ProductFamily extends AbstractDocumentEntity
return $this->productCategories;
}

public function initProductCategories()
{
$this->productCategories = new ArrayCollection() ;
}

public function addProductCategory(ProductCategory $productCategory): self
{
if (!$this->productCategories->contains($productCategory)) {

+ 9
- 0
ShopBundle/Repository/ProductCategoryRepository.php View File

@@ -31,6 +31,15 @@ class ProductCategoryRepository extends BaseRepository
->orderBy('e.position', 'ASC');
}

public function findAllParents()
{
return $this->createQueryBuilder('e')
->where('e.parent is NULL')
->andWhere('e.status >= 0')
->orderBy('e.position', 'ASC')
->getQuery()
->getResult();
}


// /**

+ 30
- 1
ShopBundle/Resources/public/css/backend/custom.css View File

@@ -18,4 +18,33 @@
.lc-ckfinder-wrap .lc-ckfinder-illu-wrap i{font-size: 5rem;}
.lc-ckfinder-wrap .lc-ckfinder-remove{border: 0px; font-size: 1.8rem; position: absolute;z-index: 2; color:#dc3545; top: -20px; right: -20px; background: 0; display: none;}

.lc-ckfinder-wrap .lc-ckfinder-button{width: 100%; bottom: 0px; left: 0; position: absolute;}
.lc-ckfinder-wrap .lc-ckfinder-button{width: 100%; bottom: 0px; left: 0; position: absolute;}

/* ProductFamily */

.new-productfamily #nav-params,
.edit-productfamily #nav-params {
margin-bottom: 30px ;
}

.new-productfamily #nav-params .btn,
.edit-productfamily #nav-params .btn {
margin-left: 20px ;
}

.new-productfamily #product-categories .row,
.edit-productfamily #product-categories .row {
padding: 10px ;
}

.new-productfamily #product-categories .form-group,
.edit-productfamily #product-categories .form-group {
width: 100% ;
padding: 4px ;
}

.new-productfamily #product-categories .children,
.edit-productfamily #product-categories .children {
margin-left: 20px ;
width: 100% ;
}

+ 0
- 72
ShopBundle/Resources/views/backend/default/edit_productfamily.html.twig View File

@@ -1,72 +0,0 @@
{% extends '@EasyAdmin/default/edit.html.twig' %}

{% block entity_form %}
{{ form_start(form) }}
<div class="lc-vue-js-container" id="lc-product-family-edit">
<div id="nav-params">
<button type="button" v-for="section in sectionsArray"
:class="'btn '+((currentSection == section.name) ? 'btn-primary' : 'btn-default')"
@click="changeSection(section)">
${ section.nameDisplay }
<span class="glyphicon glyphicon-triangle-bottom"></span>
</button>
</div>
<div class="form">
<div v-show="currentSection == 'general'" class="panel panel-default">
{{ form_row(form.title) }}
{{ form_row(form.image) }}
{{ form_row(form.description) }}

{{ form_row(form.supplier) }}
{{ form_row(form.productCategories) }}
</div>
<div v-show="currentSection == 'price'" class="panel panel-default">
{{ form_row(form.taxRate) }}

{{ form_row(form.unit, {"attr":{'v-model': 'unit'}}) }}

<div v-if="unit == 'piece'" class="form-group fiel-step">
{{ form_label(form.weight) }}
<div class="form-widget">
{{ form_widget(form.weight) }}
</div>
</div>
<div v-else class="form-group fiel-step">
{{ form_label(form.step) }}
<div class="form-widget">
{{ form_widget(form.step) }}
</div>
</div>
{#{% do form.step.setRendered %}#}

<div class="form-group fiel-step">
{{ form_label(form.price) }}
<div class="form-widget">
<div class="row m-0">
<div class="col-xs-6 mr-4">
{{ form_label(form.price) }}
{{ form_widget(form.price) }}
</div>
<div class="col-xs-6 ">
{{ form_label(form.priceWithTax) }}
{{ form_widget(form.priceWithTax) }}
</div>
</div>
</div>
</div>

{{ form_row(form.behaviorCountStock) }}
{{ form_row(form.productCategories) }}
</div>
<div v-show="currentSection == 'product'" class="panel panel-default">
{{ form_row(form.products) }}

</div>
</div>

</div>
{{ form_end(form) }}

{% endblock entity_form %}

{% block delete_form %}{% endblock %}

+ 5
- 0
ShopBundle/Resources/views/backend/default/productfamily_edit.html.twig View File

@@ -0,0 +1,5 @@
{% extends '@EasyAdmin/default/edit.html.twig' %}

{% block entity_form %}
{% include '@LcShop/backend/default/productfamily_form.html.twig' %}
{% endblock entity_form %}

+ 98
- 0
ShopBundle/Resources/views/backend/default/productfamily_form.html.twig View File

@@ -0,0 +1,98 @@
{{ form_start(form) }}
<div class="lc-vue-js-container" id="lc-product-family-edit">
<div id="nav-params">
<button type="button" v-for="section in sectionsArray"
:class="'btn '+((currentSection == section.name) ? 'btn-primary' : 'btn-default')"
@click="changeSection(section)">
${ section.nameDisplay }
<span class="glyphicon glyphicon-triangle-bottom"></span>
</button>
</div>
<div class="form">
<div v-show="currentSection == 'general'" class="panel panel-default">
<div class="row">
<div class="field-group col-6">
<fieldset>
<legend>Général</legend>
<div class="row">
<div class="col-12">
{{ form_row(form.supplier) }}
</div>
<div class="col-12">
{{ form_row(form.title) }}
</div>
<div class="col-12">
{{ form_row(form.image) }}
</div>
<div class="col-12">
{{ form_row(form.description) }}
</div>
</div>
</fieldset>
</div>
<div class="field-group col-6" id="product-categories">
<fieldset>
<legend>Catégories</legend>
<div class="row">
{% for category in categories %}
{% set child = 'category_' ~ category.id %}
{{ form_row(attribute(form.productCategories, child)) }}

{% for children in category.childrens %}
<div class="children">
{% set child = 'category_children_' ~ children.id %}
{{ form_row(attribute(form.productCategories, child), {attrs: {class: 'test'}}) }}
</div>
{% endfor %}
{% endfor %}
</div>
</fieldset>
</div>
</div>
</div>
<div v-show="currentSection == 'price'" class="panel panel-default">
{{ form_row(form.taxRate) }}

{{ form_row(form.unit, {"attr":{'v-model': 'unit'}}) }}

<div v-if="unit == 'piece'" class="form-group fiel-step">
{{ form_label(form.weight) }}
<div class="form-widget">
{{ form_widget(form.weight) }}
</div>
</div>
<div v-else class="form-group fiel-step">
{{ form_label(form.step) }}
<div class="form-widget">
{{ form_widget(form.step) }}
</div>
</div>
{#{% do form.step.setRendered %}#}

<div class="form-group fiel-step">
{{ form_label(form.price) }}
<div class="form-widget">
<div class="row m-0">
<div class="col-xs-6 mr-4">
{{ form_label(form.price) }}
{{ form_widget(form.price) }}
</div>
<div class="col-xs-6 ">
{{ form_label(form.priceWithTax) }}
{{ form_widget(form.priceWithTax) }}
</div>
</div>
</div>
</div>

{{ form_row(form.behaviorCountStock) }}
{{ form_row(form.productCategories) }}
</div>
<div v-show="currentSection == 'product'" class="panel panel-default">
{{ form_row(form.products) }}
</div>
</div>

</div>
{{ form_end(form) }}


+ 5
- 0
ShopBundle/Resources/views/backend/default/productfamily_new.html.twig View File

@@ -0,0 +1,5 @@
{% extends '@EasyAdmin/default/new.html.twig' %}

{% block entity_form %}
{% include '@LcShop/backend/default/productfamily_form.html.twig' %}
{% endblock entity_form %}

Loading…
Cancel
Save