src/Manager/AttributeManager.php line 118

Open in your IDE?
  1. <?php
  2. namespace App\Manager;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use App\Entity\Product;
  5. use App\Entity\ProductModel;
  6. use App\Entity\Category;
  7. use App\Entity\Attribute;
  8. use App\Entity\Language;
  9. use App\Entity\ProductAttribute;
  10. class AttributeManager {
  11. private $em;
  12. private $projectDir;
  13. public function __construct(EntityManagerInterface $em, \Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface $parameter)
  14. {
  15. $this->em = $em;
  16. $this->projectDir = $parameter->get('kernel.project_dir').'/';
  17. }
  18. public function createAttribute(string $code): Attribute{
  19. $attribute = new Attribute();
  20. $attribute->setCode($code);
  21. $attribute->setStatus(0);
  22. $this->em->persist($attribute);
  23. $this->em->flush();
  24. return $attribute;
  25. }
  26. public function getAttribute(string $code): ?Attribute{
  27. $attribute = $this->em->getRepository(Attribute::class)->findOneByCode($code);
  28. return $attribute ? $attribute : $this->createAttribute($code);
  29. }
  30. public function createAttributeDescription(Attribute $attribute, $isoCode = 'fr'): \App\Entity\AttributeDescription{
  31. $language = $this->em->getRepository(\App\Entity\Language::class)->findOneByCode($isoCode);
  32. $ad = new \App\Entity\AttributeDescription();
  33. $ad->setAttribute($attribute);
  34. $ad->setLanguage($language);
  35. $ad->setTitle('');
  36. return $ad;
  37. }
  38. public function createProductAttributeDescription(ProductAttribute $pa, $isoCode = 'fr'): \App\Entity\ProductAttributeDescription{
  39. $language = $this->em->getRepository(\App\Entity\Language::class)->findOneByCode($isoCode);
  40. $ad = new \App\Entity\ProductAttributeDescription();
  41. $ad->setProductAttribute($pa);
  42. $ad->setProductAttribute($pa);
  43. $ad->setLanguage($language);
  44. $ad->setValue('');
  45. return $ad;
  46. }
  47. public function addToProduct(Attribute $attribute, Product $product, string $value, $locale = null) {
  48. $pa = $this->em->getRepository('App:ProductAttribute')->findOneBy([
  49. 'attribute' => $attribute,
  50. 'product' => $product
  51. ]);
  52. if(empty($pa)) {
  53. $pa = new \App\Entity\ProductAttribute();
  54. $pa->setAttribute($attribute);
  55. $pa->setProduct($product);
  56. }
  57. if(is_null($locale)) {
  58. $pa->setValue($value);
  59. }else{
  60. $description = $pa->getDescription($locale);
  61. if(empty($description)) {
  62. $description = $this->createProductAttributeDescription($pa, $locale);
  63. }
  64. $description->setValue($value);
  65. $this->em->persist($description);
  66. }
  67. $this->em->persist($pa);
  68. $this->em->flush();
  69. }
  70. public function removeFromProduct(Attribute $attribute, Product $product) {
  71. $pas = $this->em->getRepository('App:ProductAttribute')->findBy([
  72. 'product' => $product,
  73. 'attribute' => $attribute
  74. ]);
  75. foreach($pas as $pa){
  76. $this->em->remove($pa);
  77. }
  78. $this->em->flush();
  79. }
  80. public function addToProductModel(Attribute $attribute, ProductModel $product, string $value) {
  81. $pa = $this->em->getRepository('App:ProductModelAttribute')->findOneBy([
  82. 'attribute' => $attribute,
  83. 'productModel' => $product
  84. ]);
  85. if(empty($pa)) {
  86. $pa = new \App\Entity\ProductModelAttribute();
  87. $pa->setAttribute($attribute);
  88. $pa->setProductModel($product);
  89. }
  90. $pa->setValue($value);
  91. $this->em->persist($pa);
  92. $this->em->flush();
  93. }
  94. public function removeFromProductModel(Attribute $attribute, ProductModel $model) {
  95. $pas = $this->em->getRepository('App:ProductModelAttribute')->findBy([
  96. 'productModel' => $model,
  97. 'attribute' => $attribute
  98. ]);
  99. foreach($pas as $pa){
  100. $this->em->remove($pa);
  101. }
  102. $this->em->flush();
  103. }
  104. public function getAttributesByProductModel(ProductModel $productModel): array {
  105. $attributes = [];
  106. $variant = $productModel->getVariant();
  107. if (!$variant) {
  108. return $attributes;
  109. }
  110. foreach ([$variant->getAxis1(), $variant->getAxis2()] as $axis) {
  111. if (!$axis) {
  112. continue;
  113. }
  114. $codes = array_values(array_filter(array_map('trim', explode(',', $axis))));
  115. if (count($codes) === 1) {
  116. $attribute = $this->getAttribute($codes[0]);
  117. if ($attribute && $attribute->isVariant()) {
  118. $attribute->setValues($this->getAttributeValuesByProductModel($attribute, $productModel));
  119. $attributes[] = $attribute;
  120. }
  121. } else {
  122. $composite = $this->buildCompositeAxis($codes, $productModel);
  123. if ($composite) {
  124. $attributes[] = $composite;
  125. }
  126. }
  127. }
  128. return $attributes;
  129. }
  130. /**
  131. * Builds a synthetic axis object for multi-attribute axes (e.g. axis = "taille,couleur").
  132. * Returns a stdClass with code/title/display/values so Twig can render it like a regular Attribute.
  133. * Each value has ->value (combined label "XS / Rouge") and ->product (the matching Product).
  134. */
  135. private function buildCompositeAxis(array $codes, ProductModel $productModel): ?\stdClass {
  136. $axisAttributes = [];
  137. foreach ($codes as $code) {
  138. $attr = $this->em->getRepository(Attribute::class)->findOneByCode($code);
  139. if ($attr) {
  140. $axisAttributes[] = $attr;
  141. }
  142. }
  143. if (empty($axisAttributes)) {
  144. return null;
  145. }
  146. $values = [];
  147. $seen = [];
  148. foreach ($productModel->getAllProducts() as $product) {
  149. $parts = [];
  150. foreach ($axisAttributes as $attr) {
  151. $pa = $product->getAttribute($attr->getCode());
  152. $parts[] = $pa ? ($pa->getDisplayedValue() ?? '?') : '?';
  153. }
  154. $label = implode(' / ', $parts);
  155. if (in_array($label, $seen)) {
  156. continue;
  157. }
  158. $seen[] = $label;
  159. $value = new \stdClass();
  160. $value->value = $label;
  161. $value->product = $product;
  162. $values[] = $value;
  163. }
  164. $composite = new \stdClass();
  165. $composite->code = implode(',', $codes);
  166. $composite->title = implode(' / ', array_map(fn(Attribute $a) => $a->getTitle(), $axisAttributes));
  167. $composite->display = Attribute::DISPLAY_TYPE_COMBOBOX;
  168. $composite->values = $values;
  169. return $composite;
  170. }
  171. public function getAttributeValuesByProductModel(Attribute $attribute, ProductModel $productModel) {
  172. $values = [];
  173. $tmp = [];
  174. $products = $productModel->getAllProducts();
  175. foreach($products as $product) {
  176. $attr = $product->getAttribute($attribute->getCode());
  177. if($attr && !in_array($attr->getValue(), $tmp)) {
  178. $values[] = $attr;
  179. $tmp[] = $attr->getValue();
  180. }
  181. }
  182. return $values;
  183. }
  184. }