Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [SF2][SF] Problem z tablica przy imporcie danych z csv
Forum PHP.pl > Forum > PHP > Frameworki
swiezak
Probuje dokonac importu produktow z pliku CSV i napotkalem na problem, z ktorym nie bardzo wiem, jak sobie poradzic.

Na poczatek fragment zawartosci pliku CSV:
  1. "nazwa_produktu::name";"zdjecia::product_img";"styl";"rozmiar"
  2. "produkt nr 1";"zdjecie_nr_1.jpg|zdjecie_nr_2.jpg|zdjecie_nr_3.jpg|zdjecie_nr_4.jpg";;
  3. "produkt nr 2";"zdjecie_nr_1.jpg|zdjecie_nr_2.jpg|zdjecie_nr_3.jpg";"nowoczesny|retro";"20cm"
  4. "produkt nr 3";"zdjecie_nr_1.jpg|zdjecie_nr_2.jpg";"nowoczesny|retro|klasyczny";"30cm|10cm"


W kontrolerze mam funkcje, ktora pobiera z powyzszego pliku linia po linii wartosci i tworzy tablice:
  1. public function getUploadDir()
  2. {
  3. return $this->get('kernel')->getRootDir() . '/../web/uploads/csv/';
  4. }
  5.  
  6. public function importProductsAction()
  7. {
  8. $path = $this->getUploadDir();
  9.  
  10. $row = 1;
  11. if (($handle = fopen($path."plik.csv", "r")) !== FALSE) {
  12. $products = array();
  13. while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {
  14. $num = count($data);
  15. $row++;
  16. for ($c=0; $c < $num; $c++) {
  17. $products[] = $data[$c];
  18. }
  19. }
  20. fclose($handle);
  21. }
  22. return $this->render('MlBackendBundle:ImportProducts:import_products.html.twig', array('products' => $products));
  23. }


W templatce robie dump na products i otrzymuje:
  1. array:16 [
  2. 0 => "nazwa_produktu::name"
  3. 1 => "zdjecia::product_img"
  4. 2 => "styl"
  5. 3 => "rozmiar"
  6. 4 => "produkt nr 1"
  7. 5 => "zdjecie_nr_1.jpg|zdjecie_nr_2.jpg|zdjecie_nr_3.jpg|zdjecie_nr_4.jpg"
  8. 6 => ""
  9. 7 => ""
  10. 8 => "produkt nr 2"
  11. 9 => "zdjecie_nr_1.jpg|zdjecie_nr_2.jpg|zdjecie_nr_3.jpg"
  12. 10 => "nowoczesny|retro"
  13. 11 => "20cm"
  14. 12 => "produkt nr 3"
  15. 13 => "zdjecie_nr_1.jpg|zdjecie_nr_2.jpg"
  16. 14 => "nowoczesny|retro|klasyczny"
  17. 15 => "30cm|10cm"
  18. ]


W tej tablicy jest problem - pojawia sie m.in. zapis: nazwa_produktu::name;"zdjecia::product_img" - nie wiem jak to "odfiltrowac". Naglowek ten zostal umieszczony w pliku csv, aby bylo latwiej odnalezc sie w nazwach kolumn (moze ich byc 30) i zapisywac kolejne wartosci do bazy danych.

Teraz chcialbym to jakos poprawic i pogrupowac oraz wyswietlic mniej wiecej w takiej postaci:

nazwa produktu 1: $nazwa_produktu_1
zdjecia produktu 1: foreach (...) { ... <img src="$path/$image1" alt="" /> }
rozmiar 1: ...
styl 1: ...

nazwa produktu 2: $nazwa_produktu_2
zdjecia produktu 2: foreach (...) { ... <img src="$path/$image2" alt="" /> }
rozmiar 2: ...
styl 2: ...

...

W templatce probuje zrobic cos takiego:
  1. {% if products %}
  2. {% for item in products %}
  3. {{ item|split('|') }}
  4. {% endfor %}
  5. {% else %}
  6. <p>Brak parametrow.</p>
  7. {% endif %}


Ale dostaje zwrotke w postaci:
  1. An exception has been thrown during the rendering of a template ("Notice: Array to string conversion")


No i ostatecznie sie pogubilem w tym wszystkim.
Czy ktos z Was jest w stanie mi podpwiedziec, co robie zle?

Bede wdzieczny za pomoc.
damianooo
miałem podobny komunikat o błędzie ... chyba coś miałem nie tak w tablicy ale jak dasz dumpa to klucze widzę że są OK , może chodzi o wartości ... tutaj chyba coś trzeba zrzutować

może "unset" usuń pierwsze 4 wartości z tablicy smile.gif
swiezak
Okazuje sie, ze bardzo namieszalem w kodzie.

W tej chili mam cos takiego:
  1. $row = 1;
  2.  
  3. if (($handle = fopen($path."szablon-last.csv", "r")) !== FALSE) {
  4.  
  5. fgetcsv($handle);
  6. while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {
  7. $num = count($data);
  8. $row++;
  9. for ($c=0; $c < $num; $c++) {
  10. $product = new Products();
  11. $product_sku = iconv('windows-1250', 'utf-8', $data[0]);
  12. $product->setSku($product_sku);
  13. $product_name = iconv('windows-1250', 'utf-8', $data[1]);
  14.  
  15. $product->setName($product_name);
  16.  
  17. // Zdjęcia produktów
  18. $product_images = iconv('windows-1250', 'utf-8', $data[2]);
  19. if ($product_images != NULL) {
  20. $images = new Images();
  21.  
  22. $images_chunks = explode("|", $product_images);
  23.  
  24. for ($i = 0; $i < count($images_chunks); $i++) {
  25. if (file_exists($this->getUploadDirImages().$images_chunks[$i])) {
  26.  
  27. $file = $this->getUploadDirImages().$images_chunks[$i];
  28. $image_name = $images_chunks[$i];
  29.  
  30. if (!file_exists($this->getProductImagesDir().$product_slug)) {
  31. mkdir("C:/xampp/htdocs/sklep/web/images/products/".$product_slug, 0777, true);
  32. continue;
  33. }
  34.  
  35. $newfile = $this->getProductImagesDir().$product_slug.'/'.$images_chunks[$i];
  36.  
  37. $filetmp = "C:/xampp/htdocs/sklep/web/uploads/csv/images/".$images_chunks[$i];
  38. $newfiletmp = "C:/xampp/htdocs/sklep/web/images/products/".$product_slug.'/'.$images_chunks[$i];
  39. if (!copy($filetmp, $newfiletmp)) {
  40. echo "Problem z kopiowaniem pliku: $images_chunks[$i]"."<br />";
  41. continue;
  42. }
  43.  
  44. $images->setProducts($product);
  45. $images->setFilename($image_name);
  46. $images->setIsMain(0);
  47. $images->setIsActive(1);
  48.  
  49. $manager->persist($images);
  50.  
  51. } else {
  52. echo "Brak załączonego zdjęcia: $images_chunks[$i]"."<br />";
  53. continue;
  54. }
  55. }
  56. }
  57.  
  58. $manager->persist($product);
  59. $manager->flush();
  60. }
  61. }
  62. fclose($handle);
  63. }


W tej chwili to dziala (bez dodawania atrybutow dla produktow), ale strasznie wolno. Kopiowanie zdjec pomiedzy katalogami trwa kupe czasu. Nie sa one jakies duze, maksymalnie 400 KB przypada na jedno.
Wg Was mozna jakos zoptymalizowac skrypt, aby dzialal szybciej?

I kolejna sprawa: mam produkty i kategorie paroduktow w relacji n:m oraz dodalem kolumne z nr katalogowym produktu. Kodowanie pliku z szablonem CSV to latin2/win-1250, a baze danych mam w utf-8, dlatego ten iconv.

Plik CSV wyglada teraz tak:
  1. "nr_katalogowy::sku";nazwa_produktu::name";"zdjecia::product_img";"kategorie:product_cats";"styl";"rozmiar"
  2. "a1";"produkt nr 1";"zdjecie_nr_1.jpg|zdjecie_nr_2.jpg|zdjecie_nr_3.jpg|zdjecie_nr_4.jpg";"kategorie|kabiny|prysznicowe";;
  3. "a2";"produkt nr 2";"zdjecie_nr_1.jpg|zdjecie_nr_2.jpg|zdjecie_nr_3.jpg";"kategorie|kabiny|prysznicowe";"nowoczesny|retro";"20cm"
  4. "a3";"produkt nr 3";"zdjecie_nr_1.jpg|zdjecie_nr_2.jpg";"kategorie|kabiny|prysznicowe";"nowoczesny|retro|klasyczny";"30cm|10cm"


Fragment z kontrolera:
  1. $row = 1;
  2.  
  3. if (($handle = fopen($path."szablon-last.csv", "r")) !== FALSE) {
  4.  
  5. fgetcsv($handle);
  6. while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {
  7. $num = count($data);
  8. $row++;
  9. for ($c=0; $c < $num; $c++) {
  10. $product = new Products();
  11. $product_sku = iconv('windows-1250', 'utf-8', $data[0]);
  12. $product->setSku($product_sku);
  13. $product_name = iconv('windows-1250', 'utf-8', $data[1]);
  14.  
  15. $product->setName($product_name);
  16.  
  17. $product_slug = $this->slugify($product_name);
  18. $product->setSlug($product_slug); // Przyjazny link
  19.  
  20. $product_categories = iconv('windows-1250', 'utf-8', $data[3]);
  21. if ($product_categories != NULL) {
  22. $categories_chunks = explode("|", $product_categories);
  23. $cat = (count($categories_chunks) - 1); // wartosc zmiennej to "prysznicowe"
  24. }
  25.  
  26. // Zdjęcia produktów
  27. $product_images = iconv('windows-1250', 'utf-8', $data[2]);
  28. if ($product_images != NULL) {
  29. $images = new Images();
  30.  
  31. $images_chunks = explode("|", $product_images);
  32.  
  33. for ($i = 0; $i < count($images_chunks); $i++) {
  34. if (file_exists($this->getUploadDirImages().$images_chunks[$i])) {
  35.  
  36. $file = $this->getUploadDirImages().$images_chunks[$i];
  37. $image_name = $images_chunks[$i];
  38.  
  39. if (!file_exists($this->getProductImagesDir().$product_slug)) {
  40. mkdir("C:/xampp/htdocs/sklep/web/images/products/".$product_slug, 0777, true);
  41. continue;
  42. }
  43.  
  44. $newfile = $this->getProductImagesDir().$product_slug.'/'.$images_chunks[$i];
  45.  
  46. $filetmp = "C:/xampp/htdocs/sklep/web/uploads/csv/images/".$images_chunks[$i];
  47. $newfiletmp = "C:/xampp/htdocs/sklep/web/images/products/".$product_slug.'/'.$images_chunks[$i];
  48. if (!copy($filetmp, $newfiletmp)) {
  49. echo "Problem z kopiowaniem pliku: $images_chunks[$i]"."<br />";
  50. continue;
  51. }
  52.  
  53. $images->setProducts($product);
  54. $images->setFilename($image_name);
  55. $images->setIsMain(0);
  56. $images->setIsActive(1);
  57.  
  58. $manager->persist($images);
  59.  
  60. } else {
  61. echo "Brak załączonego zdjęcia: $images_chunks[$i]"."<br />";
  62. continue;
  63. }
  64. }
  65. }
  66.  
  67. $manager->persist($product);
  68. $manager->flush();
  69. }
  70. }
  71. fclose($handle);
  72. }


Encja produktow:
  1. /**
  2.  * Products
  3.  *
  4.  * @ORM\Table()
  5.  * @ORM\Entity(repositoryClass="Ml\FrontendBundle\Entity\ProductsRepository")
  6.  */
  7. class Products
  8. {
  9. ...
  10.  
  11. /**
  12.   * @ORM\OneToMany(targetEntity="Images", mappedBy="products", cascade={"persist"})
  13.   */
  14. protected $images;
  15.  
  16. /**
  17.   * @ORM\OneToMany(targetEntity="Attributes", mappedBy="products", cascade={"persist"})
  18.   */
  19. protected $attributes;
  20.  
  21. /**
  22.   * @ORM\ManyToMany(targetEntity="Categories", inversedBy="products")
  23.   */
  24. protected $categories;
  25.  
  26. public function __toString() {
  27. return $this->name;
  28. }
  29.  
  30. ...
  31.  
  32. /**
  33.   * Constructor
  34.   */
  35. public function __construct()
  36. {
  37. $this->images = new \Doctrine\Common\Collections\ArrayCollection();
  38. $this->attributes = new \Doctrine\Common\Collections\ArrayCollection();
  39. $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
  40. }
  41.  
  42. ...
  43.  
  44. /**
  45.   * Add category
  46.   *
  47.   * @param \Ml\FrontendBundle\Entity\Categories $category
  48.   *
  49.   * @return Products
  50.   */
  51. public function addCategory(\Ml\FrontendBundle\Entity\Categories $category)
  52. {
  53. $this->categories[] = $category;
  54.  
  55. return $this;
  56. }
  57.  
  58. /**
  59.   * Remove category
  60.   *
  61.   * @param \Ml\FrontendBundle\Entity\Categories $category
  62.   */
  63. public function removeCategory(\Ml\FrontendBundle\Entity\Categories $category)
  64. {
  65. $this->categories->removeElement($category);
  66. }
  67.  
  68. /**
  69.   * Get categories
  70.   *
  71.   * @return \Doctrine\Common\Collections\Collection
  72.   */
  73. public function getCategories()
  74. {
  75. return $this->categories;
  76. }
  77. ...
  78.  


Encja kategorii:
  1. /**
  2.  * Categories
  3.  *
  4.  * @Gedmo\Tree(type="nested")
  5.  * @ORM\Table(name="categories")
  6.  * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
  7.  */
  8. class Categories
  9. {
  10. /**
  11.   * @var integer
  12.   * @ORM\Column(name="id", type="integer")
  13.   * @ORM\Id
  14.   * @ORM\GeneratedValue(strategy="AUTO")
  15.   */
  16. private $id;
  17.  
  18. /**
  19.   * @var string
  20.   *
  21.   * @Assert\NotBlank()
  22.   * @ORM\Column(name="name", type="string", length=255)
  23.   */
  24. private $name;
  25.  
  26. /**
  27. * @var string $slug
  28. *
  29. * @Gedmo\Slug(fields={"name"})
  30. * @ORM\Column(length=255, unique=true)
  31. */
  32. private $slug;
  33.  
  34.  
  35. // gedmo tree
  36.  
  37. /**
  38.   * @ORM\ManyToMany(targetEntity="Products", mappedBy="categories")
  39.   */
  40. protected $products;
  41.  
  42. /**
  43.   * @ORM\ManyToMany(targetEntity="Attributes", mappedBy="categories")
  44.   */
  45. protected $attributes;
  46.  
  47. ...
  48.  
  49. public function __toString() {
  50. return $this->name;
  51. }
  52.  
  53. /**
  54.   * Constructor
  55.   */
  56. public function __construct()
  57. {
  58. $this->children = new \Doctrine\Common\Collections\ArrayCollection();
  59. $this->products = new \Doctrine\Common\Collections\ArrayCollection();
  60. $this->attributes = new \Doctrine\Common\Collections\ArrayCollection();
  61. }
  62.  
  63. ...
  64.  
  65. /**
  66.   * Add product
  67.   *
  68.   * @param \Ml\FrontendBundle\Entity\Products $product
  69.   *
  70.   * @return Categories
  71.   */
  72. public function addProduct(\Ml\FrontendBundle\Entity\Products $product)
  73. {
  74. $this->products[] = $product;
  75.  
  76. return $this;
  77. }
  78.  
  79. /**
  80.   * Remove product
  81.   *
  82.   * @param \Ml\FrontendBundle\Entity\Products $product
  83.   */
  84. public function removeProduct(\Ml\FrontendBundle\Entity\Products $product)
  85. {
  86. $this->products->removeElement($product);
  87. }
  88.  
  89. /**
  90.   * Get products
  91.   *
  92.   * @return \Doctrine\Common\Collections\Collection
  93.   */
  94. public function getProducts()
  95. {
  96. return $this->products;
  97. }
  98.  
  99. ...
  100.  


Mam problem z zapisem id produktu i id kategorii do tabeli laczacej "products_categories";
Czy ktos mi pomoze?
Savage.Mephisto
To banalnie proste.

Zrób w ten sposób:
  1. $product_categories = iconv('windows-1250', 'utf-8', $data[3]);
  2.  
  3. if ($product_categories != NULL) {
  4. $categories_chunks = explode("|", $product_categories);
  5. $cat = (count($categories_chunks) - 1);
  6. $cat_name = $categories_chunks[$cat];
  7.  
  8. $Category = $manager->getRepository('MlBackendBundle:Categories')
  9. ->findOneByName($cat_name);
  10. $product->addCategory($Category);
  11. }
swiezak
Ok, dziala. Wielkie dzieki.

A co zrobic z wydajnoscia skryptu? Da rade dokonac jakiejs optymalizacji, bo mam do zaimportowania 5000 produktow.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.